GNU/Linux >> Znalost Linux >  >> Linux

Vyvolat chybu ve skriptu Bash

Existuje několik dalších způsobů, jak se k tomuto problému postavit. Za předpokladu, že jedním z vašich požadavků je spustit skript/funkci shellu obsahující několik příkazů shellu a zkontrolovat, zda skript úspěšně proběhl, a v případě selhání vyvolat chyby.

Příkazy shellu obecně spoléhají na návratové kódy, aby shell věděl, zda byl úspěšný nebo selhal kvůli nějakým neočekávaným událostem.

Takže to, co chcete dělat, spadá do těchto dvou kategorií

  • ukončit při chybě
  • ukončit a provést vyčištění při chybě

V závislosti na tom, kterou z nich chcete provést, jsou k dispozici možnosti prostředí. V prvním případě poskytuje shell možnost s set -e a za druhé můžete udělat trap dne EXIT

Mám použít exit v mém skriptu/funkci?

Pomocí exit obecně zlepšuje čitelnost V určitých rutinách, jakmile znáte odpověď, chcete okamžitě ukončit volající rutinu. Pokud je rutina definována tak, že po zjištění chyby nevyžaduje žádné další čištění, neukončení okamžitě znamená, že musíte napsat další kód.

Takže v případech, kdy potřebujete provést vyčištění skriptu, aby bylo ukončení skriptu čisté, je lepší ne použít exit .

Mám použít set -e za chybu při ukončení?

Ne!

set -e byl pokus přidat do shellu „automatickou detekci chyb“. Jeho cílem bylo způsobit přerušení shellu, kdykoli dojde k chybě, ale přichází s mnoha potenciálními úskalími, například

  • Příkazy, které jsou součástí testu if, jsou imunní. V příkladu, pokud očekáváte, že se zlomí na test zkontrolujte neexistující adresář, nebylo by to, přejde to do podmínky else

    set -e
    f() { test -d nosuchdir && echo no dir; }
    f
    echo survived
    
  • Příkazy v jiném potrubí, než je ten poslední, jsou imunní. V níže uvedeném příkladu proto, že se bere v úvahu kód ukončení posledního provedeného (úplně vpravo) příkazu ( cat ) a bylo to úspěšné. Tomu by se dalo předejít nastavením pomocí set -o pipefail možnost, ale stále je to varování.

    set -e
    somecommand that fails | cat -
    echo survived 
    

Doporučeno pro použití – trap při výstupu

Verdikt zní, pokud chcete být schopni zvládnout chybu namísto slepého ukončení, namísto použití set -e , použijte trap na ERR pseudo signál.

ERR past není spustit kód, když se samotný shell ukončí s nenulovým chybovým kódem, ale když je spuštěn jakýkoli příkaz tímto shellem, který není součástí podmínky (jako v if cmd nebo cmd || ) ukončí se s nenulovým stavem ukončení.

Obecnou praxí je, že definujeme obslužnou rutinu pasti, která poskytuje další informace o ladění na kterém řádku a co způsobuje ukončení. Pamatujte si výstupní kód posledního příkazu, který způsobil ERR signál bude v tuto chvíli stále dostupný.

cleanup() {
    exitcode=$?
    printf 'error condition hit\n' 1>&2
    printf 'exit code returned: %s\n' "$exitcode"
    printf 'the command executing at the time of the error was: %s\n' "$BASH_COMMAND"
    printf 'command present on line: %d' "${BASH_LINENO[0]}"
    # Some more clean up code can be added here before exiting
    exit $exitcode
}

a my pouze použijeme tuto obsluhu, jak je uvedeno níže, nad skriptem, který selhává

trap cleanup ERR

Dát to dohromady do jednoduchého skriptu, který obsahoval false na řádku 15 informace, které byste získali jako

error condition hit
exit code returned: 1
the command executing at the time of the error was: false
command present on line: 15

trap také poskytuje možnosti bez ohledu na chybu jednoduše spustit vyčištění po dokončení shellu (např. ukončení skriptu shellu), na signálu EXIT . Můžete také zachytit více signálů současně. Seznam podporovaných signálů k zachycení lze nalézt na trap.1p - Linux manual page

Další věcí, které je třeba si povšimnout, je pochopit, že žádná z poskytnutých metod nefunguje, pokud máte co do činění s dílčími shelly, v takovém případě možná budete muset přidat vlastní zpracování chyb.

  • Na sub-shell s set -e by nefungovalo. false je omezena na podskořápku a nikdy se nešíří do nadřazeného prostředí. Chcete-li provést zpracování chyb zde, přidejte vlastní logiku k provedení (false) || false

    set -e
    (false)
    echo survived
    
  • Totéž se děje s trap taky. Níže uvedená logika by nefungovala z výše uvedených důvodů.

    trap 'echo error' ERR
    (false)
    

Zpracování základních chyb

Pokud váš testovací případ vrátí nenulový kód pro neúspěšné testy, můžete jednoduše napsat:

test_handler test_case_x; test_result=$?
if ((test_result != 0)); then
  printf '%s\n' "Test case x failed" >&2  # write error message to stderr
  exit 1                                  # or exit $test_result
fi

Nebo ještě kratší:

if ! test_handler test_case_x; then
  printf '%s\n' "Test case x failed" >&2
  exit 1
fi

Nebo nejkratší:

test_handler test_case_x || { printf '%s\n' "Test case x failed" >&2; exit 1; }

Ukončení pomocí ukončovacího kódu test_handler:

test_handler test_case_x || { ec=$?; printf '%s\n' "Test case x failed" >&2; exit $ec; }

Pokročilé zpracování chyb

Pokud chcete použít komplexnější přístup, můžete mít obslužný program chyb:

exit_if_error() {
  local exit_code=$1
  shift
  [[ $exit_code ]] &&               # do nothing if no error code passed
    ((exit_code != 0)) && {         # do nothing if error code is 0
      printf 'ERROR: %s\n' "[email protected]" >&2 # we can use better logging here
      exit "$exit_code"             # we could also check to make sure
                                    # error code is numeric when passed
    }
}

poté jej vyvolejte po spuštění testovacího případu:

run_test_case test_case_x
exit_if_error $? "Test case x failed"

nebo

run_test_case test_case_x || exit_if_error $? "Test case x failed"

Výhody obslužného programu chyb jako exit_if_error jsou:

  • můžeme standardizovat veškerou logiku zpracování chyb, jako je protokolování, tisk trasování zásobníku, upozornění, čištění atd., na jednom místě
  • tím, že obslužné rutině chyb přijmeme chybový kód jako argument, můžeme volajícího ušetřit změti if bloky, které testují výstupní kódy na chyby
  • pokud máme obslužnou rutinu signálu (pomocí pasti), můžeme obslužnou rutinu chyb vyvolat odtud

Knihovna zpracování chyb a protokolování

Zde je kompletní implementace zpracování chyb a protokolování:

https://github.com/codeforester/base/blob/master/lib/stdlib.sh

Související příspěvky

  • Zpracování chyb v Bash
  • Vestavěný příkaz 'caller' na Bash Hackers Wiki
  • Existují v systému Linux nějaké standardní kódy stavu ukončení?
  • BashFAQ/105 – Proč nastavení -e (nebo nastavení -o errexit nebo past ERR) nedělá to, co jsem očekával?
  • Ekvivalent __FILE__ , __LINE__ v Bash
  • Je v Bash příkaz TRY CATCH
  • Chcete-li přidat trasování zásobníku do obslužné rutiny chyb, můžete se podívat na tento příspěvek:Trasování spuštěných programů volaných skriptem Bash
  • Ignorování konkrétních chyb ve skriptu shellu
  • Zachycení chybových kódů v shell pipe
  • Jak mohu spravovat podrobnost protokolu uvnitř skriptu shellu?
  • Jak zaznamenat název funkce a číslo řádku v Bash?
  • Jsou v Bash vhodnější dvojité hranaté závorky [[ ]] před jednoduchými hranatými závorkami [ ]?

To závisí na tom, kam chcete chybovou zprávu uložit.

Můžete provést následující:

echo "Error!" > logfile.log
exit 125

Nebo následující:

echo "Error!" 1>&2
exit 64

Když vyvoláte výjimku, zastavíte provádění programu.

Můžete také použít něco jako exit xxx kde xxx je kód chyby, který můžete chtít vrátit do operačního systému (od 0 do 255). Zde 125 a 64 jsou pouze náhodné kódy, pomocí kterých můžete odejít. Když potřebujete operačnímu systému oznámit, že se program nenormálně zastavil (např. došlo k chybě), musíte předat nenulový kód ukončení na exit .

Jak zdůraznil @chepner, můžete udělat exit 1 , což bude znamenat nespecifikovanou chybu .


Linux
  1. Naučte se zpracování chyb Bash na příkladu

  2. Může být Bash skript připojen k souboru?

  3. Sazba -a Je zadávání chyby ve skriptu?

  1. Bash skript k vyplnění šablony?

  2. Chyba skriptu Bash:Očekává se celočíselný výraz?

  3. Spusťte bash skript z adresy URL

  1. alternativy --config java bash skript

  2. Co znamená set -e ve skriptu bash?

  3. Spusťte příkaz bash na jenkins pipeline