Domanda

Ho uno script di shell che esegue una serie di comandi.Come faccio a far uscire lo script della shell se uno qualsiasi dei comandi esce con un codice di uscita diverso da zero?

È stato utile?

Soluzione

Dopo ogni comando, il codice di uscita può essere trovato nel file $? variabile quindi avresti qualcosa del tipo:

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

È necessario fare attenzione ai comandi trasmessi poiché il file $? ti dà solo il codice di ritorno dell'ultimo elemento nella pipe quindi, nel codice:

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

non restituirà un codice di errore se il file non esiste (poiché il file sed parte della pipeline funziona effettivamente, restituendo 0).

IL bash shell in realtà fornisce un array che può aiutare in quel caso, cioè PIPESTATUS.Questo array ha un elemento per ciascuno dei componenti della pipeline, a cui puoi accedere individualmente ${PIPESTATUS[0]}:

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

Nota che questo ti sta dando il risultato di false comando, non l'intera pipeline.Puoi anche far elaborare l'intero elenco come ritieni opportuno:

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

Se volessi ottenere il codice di errore più grande da una pipeline, potresti usare qualcosa come:

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

Questo passa attraverso ciascuno dei PIPESTATUS elementi a loro volta, memorizzandoli rc se fosse maggiore del precedente rc valore.

Altri suggerimenti

Se vuoi lavorare con $?, dovrai controllarlo dopo ogni comando, poiché $?viene aggiornato dopo l'uscita di ogni comando.Ciò significa che se esegui una pipeline, otterrai solo il codice di uscita dell'ultimo processo nella pipeline.

Un altro approccio è quello di fare questo:

set -e
set -o pipefail

Se lo metti in cima allo script della shell, sembra che bash se ne occuperà per te.Come notato in precedenza, "set -e" farà sì che bash esca con un errore su qualsiasi comando semplice."set -o pipefail" farà sì che bash esca con un errore anche su qualsiasi comando in una pipeline.

Vedere Qui O Qui per una discussione più approfondita su questo problema. Qui è la sezione manuale di bash sul set integrato.

"set -e" è probabilmente il modo più semplice per farlo.Mettilo prima di qualsiasi comando nel tuo programma.

Se chiami semplicemente exit nella bash senza parametri, restituirà il codice di uscita dell'ultimo comando.Combinato con OR la ​​bash dovrebbe invocare exit solo se il comando precedente fallisce.Ma non l'ho testato.

command1 || exit;
command2 || exit;

La Bash memorizzerà anche il codice di uscita dell'ultimo comando nella variabile $?.

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

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

  1. Come posso ottenere il codice di uscita di cmd1 In cmd1|cmd2

    Innanzitutto, notalo cmd1 Il codice di uscita potrebbe essere diverso da zero e ancora non significare un errore.Ciò accade ad esempio in

    cmd | head -1
    

    potresti osservare uno stato di uscita 141 (o 269 con ksh93). cmd1, ma è perché cmd è stato interrotto da un segnale SIGPIPE quandohead -1 terminato dopo aver letto una riga.

    Conoscere lo stato di uscita degli elementi di una pipelinecmd1 | cmd2 | cmd3

    UN.con zsh:

    I codici di uscita sono forniti nell'array speciale pipestatus. cmd1 il codice di uscita è inserito $pipestatus[1], cmd3 codice di uscita in $pipestatus[3], affinché $? è sempre lo stesso di $pipestatus[-1].

    B.con bash:

    I codici di uscita sono forniti nel file PIPESTATUS matrice speciale. cmd1 il codice di uscita è inserito ${PIPESTATUS[0]}, cmd3 codice di uscita in ${PIPESTATUS[2]}, affinché $? è sempre lo stesso di ${PIPESTATUS: -1}.

    ...

    Per maggiori dettagli vedere quanto segue collegamento.

per 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;
}

In bash è facile, basta collegarli insieme con &&:

command1 && command2 && command3

Puoi anche usare il costrutto nidificato if:

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

    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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top