it-swarm-eu.dev

Ukončete Shell skript založený na Process Exit Code

Mám skript Shell, který provádí řadu příkazů. Jak provedu ukončení skriptu Shell, pokud některý z příkazů skončí s nenulovým kódem ukončení?

364
Mark Roddy

Po každém příkazu lze výstupní kód nalézt v proměnné $?, takže byste měli něco jako:

ls -al file.ext
rc=$?; if [[ $rc != 0 ]]; then exit $rc; fi

Musíte být opatrní na příkazy piped, protože $? vám dává pouze návratový kód posledního prvku v potrubí, takže v kódu:

ls -al file.ext | sed 's/^/xx: /"

nevrátí chybový kód, pokud soubor neexistuje (protože sed část potrubí skutečně funguje, vrací 0).

Shell bash Shell skutečně poskytuje pole, které může v tomto případě pomoci, a to PIPESTATUS. Toto pole obsahuje jeden prvek pro každou ze součástí potrubí, ke kterému můžete přistupovat jednotlivě jako ${PIPESTATUS[0]}:

pax> false | true ; echo ${PIPESTATUS[0]}
1

Všimněte si, že tím získáváte výsledek příkazu false, nikoli celého potrubí. Můžete také nechat zpracovat celý seznam, jak uznáte za vhodné:

pax> false | true | false; echo ${PIPESTATUS[*]}
1 0 1

Pokud jste chtěli získat největší chybový kód z potrubí, můžete použít něco jako:

true | true | false | true | false
rcs=${PIPESTATUS[*]}; rc=0; for i in ${rcs}; do rc=$(($i > $rc ? $i : $rc)); done
echo $rc

Tím prochází každý z prvků PIPESTATUS, přičemž je uložen v rc, pokud byl větší než předchozí hodnota rc.

469
paxdiablo

Pokud chcete pracovat s $?, Musíte jej zkontrolovat po každém příkazu, protože $? je aktualizován po ukončení každého příkazu. To znamená, že pokud provedete potrubí, dostanete pouze výstupní kód posledního procesu v potrubí.

Dalším přístupem je to:

set -e
set -o pipefail

Pokud to umístíte na začátek skriptu Shell, vypadá to, že se o to postará bash. Jak poznamenal předchozí plakát, „set -e“ způsobí ukončení bash s chybou při jakémkoli jednoduchém příkazu. "set -o pipefail" způsobí ukončení bash s chybou na jakémkoli příkazu v potrubí.

Podívejte se na zde nebo zde pro trochu více diskuse o tomto problému. Zde je sekce bash manuálu na vestavěném souboru.

213
Jeff Hill

"set -e" je pravděpodobně nejjednodušší způsob, jak toho dosáhnout. Prostě to dejte před jakékoli příkazy v programu.

50
Allen

Pokud zavoláte exit v bash bez parametrů, vrátí výstupní kód posledního příkazu. V kombinaci s OR by bash měl vyvolat exit, pokud předchozí příkaz selže. Ale tohle jsem netestoval.

 příkaz 1 || exit; 
 příkaz2 || výstup;

Bash také uloží výstupní kód posledního příkazu do proměnné $ ?.

28
Arvodan
[ $? -eq 0 ] || exit $?; # exit for none-zero return code
25
chemila

http://cfaj.freeshell.org/Shell/cus-faq-2.html#11

  1. Jak získám výstupní kód cmd1 v cmd1|cmd2

    Nejprve si všimněte, že výstupní kód cmd1 může být nenulový a stále ještě neznamená chybu. To se děje například v

    cmd | head -1
    

    můžete sledovat stav výstupu 141 (nebo 269 s ksh93) cmd1, ale je to proto, že cmd byl přerušen signálem SIGPIPE, když head -1 ukončeno po přečtení jednoho řádku.

    Znát stav výstupu prvků potrubí cmd1 | cmd2 | cmd3

    a. se zsh:

    Výstupní kódy jsou uvedeny ve speciálním poli pipestatus. Výstupní kód cmd1 je v $pipestatus[1], cmd3 exit code v $pipestatus[3], takže $? je vždy stejný jako $pipestatus[-1].

    b. s bash:

    Výstupní kódy jsou uvedeny ve speciálním poli PIPESTATUS. Výstupní kód cmd1 je v ${PIPESTATUS[0]}, cmd3 exit code v ${PIPESTATUS[2]}, takže $? je vždy stejný jako ${PIPESTATUS: -1}.

    ...

    Více podrobností viz následující link .

21

pro bash:

# this will trap any errors or commands with non-zero exit status
# by calling function catch_errors()
trap catch_errors ERR;

#
# ... the rest of the script goes here
#  

function catch_errors() {
   # do whatever on errors
   # 
   #
   echo "script aborted, because of errors";
   exit 0;
}
19

V bash je to snadné, stačí je spojit s &&:

command1 && command2 && command3

Vnořené můžete také použít, pokud je konstruováno:

if command1
   then
       if command2
           then
               do_something
           else
               exit
       fi
   else
       exit
fi
11
Martin W
#
#------------------------------------------------------------------------------
# run a command on failure exit with message
# doPrintHelp: doRunCmdOrExit "$cmd"
# call by:
# set -e ; doRunCmdOrExit "$cmd" ; set +e
#------------------------------------------------------------------------------
doRunCmdOrExit(){
    cmd="[email protected]" ;

    doLog "DEBUG running cmd or exit: \"$cmd\""
    msg=$($cmd 2>&1)
    export exit_code=$?

    # if occured during the execution exit with error
    error_msg="Failed to run the command:
        \"$cmd\" with the output:
        \"$msg\" !!!"

    if [ $exit_code -ne 0 ] ; then
        doLog "ERROR $msg"
        doLog "FATAL $msg"
        doExit "$exit_code" "$error_msg"
    else
        #if no errors occured just log the message
        doLog "DEBUG : cmdoutput : \"$msg\""
        doLog "INFO  $msg"
    fi

}
#eof func doRunCmdOrExit
4
Yordan Georgiev