it-swarm-tr.com

İşlem Çıkış Koduna Göre Kabuk Betiğinden Çıkma

Birkaç komut yürüten bir Shell betiğim var. Komutlardan herhangi biri sıfır olmayan bir çıkış koduyla çıkarsa, Shell komut dosyasının çıkışını nasıl yaparım?

364
Mark Roddy

Her komuttan sonra, çıkış kodu $? değişkeninde bulunabilir, böylece şöyle bir şeye sahip olabilirsiniz:

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

Borulu komutlara dikkat etmeniz gerekir, çünkü $?, yalnızca size koddaki son öğenin dönüş kodunu verdiğinden, kodda:

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

dosya mevcut değilse bir hata kodu döndürmez (boru hattının sedkısmı gerçekten çalıştığından, 0 döndürür).

bashShell aslında bu durumda PIPESTATUSolan yardımcı olabilecek bir dizi sağlar. Bu dizinin her biri, ${PIPESTATUS[0]} gibi ayrı ayrı erişebildiğiniz her boru hattı bileşeni için bir öğe içerir:

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

Bunun, tüm boru hattının değil, falsekomutunun sonucunu elde ettiğini unutmayın. Ayrıca listenin tamamını uygun gördüğünüz şekilde işlemden geçirebilirsiniz:

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

Bir boru hattından en büyük hata kodunu almak istiyorsanız, aşağıdaki gibi bir şey kullanabilirsiniz:

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

Bu, PIPESTATUSöğelerinin her birinden geçer, önceki rcdeğerinden büyükse, rcöğesinde saklar.

469
paxdiablo

$? İle çalışmak istiyorsanız, $ 'dan beri her komuttan sonra kontrol etmeniz gerekir. Her komut çıktıktan sonra güncellenir. Bunun anlamı, bir boru hattını yürütürseniz, sadece boru hattındaki son işlemin çıkış kodunu alırsınız.

Başka bir yaklaşım da bunu yapmaktır:

set -e
set -o pipefail

Bunu Shell betiğinin en üstüne koyarsanız, bash bunu sizin için halledecek gibi görünüyor. Daha önce belirtildiği gibi, "set -e" ifadesi bash'ın herhangi bir basit komutta bir hatayla çıkmasına neden olacaktır. "set -o pipefail", boru hattındaki herhangi bir komutta da bash hatası vermesine neden olacaktır.

Bu sorun hakkında biraz daha tartışma için bakınız burada veya burada . Here , setin yerleşik kısmındaki bash manuel bölümüdür.

213
Jeff Hill

"set -e" muhtemelen bunu yapmanın en kolay yoludur. Bunu programınızdaki herhangi bir komuttan önce koyun.

50
Allen

Bash'ta parametresiz sadece exit çağırırsanız, son komutun çıkış kodunu döndürür. OR ile birleştirildiğinde bash, önceki komut başarısız olursa yalnızca çıkışı çağırmalıdır. Ama bunu test etmedim.

 komut1 || exit; 
 command2 || çıkış;

Bash ayrıca son komutun çıkış kodunu $? Değişkeninde saklar.

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

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

  1. cmd1'ın çıkış kodunu cmd1|cmd2 içinde nasıl alabilirim

    İlk olarak, cmd1 çıkış kodunun sıfır olamayacağını ve hala bir hata anlamına gelmediğini unutmayın. Bu, örneğin

    cmd | head -1
    

    cmd1'nin 141 (veya ksh93 ile 269) çıkış durumunu gözlemleyebilirsiniz, ancak bunun nedeni cmdname__'ın bir satır okuduktan sonra head -1 sonlandırıldığında SIGPIPE sinyali tarafından kesilmesidir.

    Bir boru hattı elemanlarının çıkış durumunu bilmek cmd1 | cmd2 | cmd3

    a. zsh ile:

    Çıkış kodları pipestatus özel dizisinde verilmiştir. cmd1 çıkış kodu $pipestatus[1], cmd3 çıkış kodu, $pipestatus[3] içinde, böylece $? her zaman $pipestatus[-1] ile aynı olur.

    b. bash ile:

    Çıkış kodları PIPESTATUSözel dizisinde bulunur. cmd1 çıkış kodu ${PIPESTATUS[0]}, cmd3 çıkış kodu, ${PIPESTATUS[2]} içinde, böylece $? her zaman ${PIPESTATUS: -1} ile aynı olur.

    ...

    Daha fazla ayrıntı için aşağıdakilere bakın link .

21

bash için:

# 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

Kısaca, bu kolaydır, sadece && ile birlikte bağlamanız yeterlidir:

command1 && command2 && command3

Eğer yapı içindeyse iç içe de kullanabilirsiniz:

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