Programing

오류 발생시 bash 쉘 스크립트에서 자동 종료

lottogame 2020. 10. 4. 10:12
반응형

오류 발생시 bash 쉘 스크립트에서 자동 종료


몇 가지 셸 스크립트를 작성 중이며 명령 중 하나라도 실패하면 해당 셸 스크립트의 실행을 중지 할 수있는 기능이 있으면 유용합니다. 예는 아래를 참조하십시오.

#!/bin/bash  

cd some_dir  

./configure --some-flags  

make  

make install

따라서이 경우 스크립트가 표시된 디렉토리로 변경할 수없는 경우 실패하면 나중에 ./configure를 수행하고 싶지 않을 것입니다.

이제 각 명령에 대해 if 검사를 할 수 있다는 것을 잘 알고 있습니다 (절망적 인 해결책이라고 생각합니다).하지만 명령 중 하나가 실패 할 경우 스크립트를 종료하는 전역 설정이 있습니까?


set -e내장 사용 :

#!/bin/bash
set -e
# Any subsequent(*) commands which fail will cause the shell script to exit immediately

또는 -e명령 줄에서 전달할 수 있습니다 .

bash -e my_script.sh

사용 하여이 동작을 비활성화 할 수도 있습니다 set +e.

다음 -e -u -x-o pipefail같이 옵션 의 전부 또는 일부를 사용할 수도 있습니다 .

set -euxo pipefail

-e오류시 종료, -u정의되지 않은 변수 오류 및 -o (for option) pipefail명령 파이프 실패시 종료됩니다. 일부 문제와 해결 방법은 여기에 잘 설명되어 있습니다 .

(*) 노트:

실패한 명령이 while 또는 until 키워드 바로 뒤에 오는 명령 목록의 일부, if 또는 elif 예약어 다음에 오는 테스트의 일부, && 또는 || 에서 실행되는 명령의 일부인 경우 쉘은 종료 되지 않습니다. 마지막 && 또는 || 다음에 오는 명령을 제외한 목록 , 파이프 라인에 있지만 마지막 명령이거나 명령의 반환 값이 !

(부터 man bash)


명령 중 하나가 실패하자마자 스크립트를 종료하려면 처음에 다음을 추가하십시오.

set -e

이로 인해 일부 테스트의 일부가 아닌 일부 명령 (예 : if [ ... ]조건 또는 &&구성)이 0이 아닌 종료 코드 로 종료 될 때 스크립트가 즉시 종료됩니다.


방법은 다음과 같습니다.

#!/bin/sh

abort()
{
    echo >&2 '
***************
*** ABORTED ***
***************
'
    echo "An error occurred. Exiting..." >&2
    exit 1
}

trap 'abort' 0

set -e

# Add your script below....
# If an error occurs, the abort() function will be called.
#----------------------------------------------------------
# ===> Your script goes here
# Done!
trap : 0

echo >&2 '
************
*** DONE *** 
************
'

와 함께 사용하십시오 pipefail.

set -e
set -o pipefail

-e (errexit) : 명령이 0이 아닌 상태로 종료 될 때 첫 번째 오류시 스크립트 중단 (until 또는 while 루프, if-tests, 목록 구성 제외)

-o pipefail : 파이프 라인이 0이 아닌 반환 값을 반환 한 파이프에서 마지막 명령의 종료 상태를 반환하도록합니다.

33 장. 옵션


첫 번째 줄에 맞는 수락 된 답변의 대안 :

#!/bin/bash -e

cd some_dir  

./configure --some-flags  

make  

make install

관용구 중 하나는 다음과 같습니다.

cd some_dir && ./configure --some-flags && make && make install

오래 걸릴 수 있지만 더 큰 스크립트의 경우 논리 함수로 나눌 수 있습니다.


나는 당신이 찾고있는 것이 trap명령 이라고 생각합니다 .

trap command signal [signal ...]

For more information, see this page.

Another option is to use the set -e command at the top of your script - it will make the script exit if any program / command returns a non true value.


One point missed in the existing answers is show how to inherit the error traps. The bash shell provides one such option for that using set

-E

If set, any trap on ERR is inherited by shell functions, command substitutions, and commands executed in a subshell environment. The ERR trap is normally not inherited in such cases.


Adam Rosenfield's answer recommendation to use set -e is right in certain cases but it has its own potential pitfalls. See GreyCat's BashFAQ - 105 - Why doesn't set -e (or set -o errexit, or trap ERR) do what I expected?

According to the manual, set -e exits

if a simple commandexits with a non-zero status. The shell does not exit if the command that fails is part of the command list immediately following a while or until keyword, part of the test in a if statement, part of an && or || list except the command following the final && or ||, any command in a pipeline but the last, or if the command's return value is being inverted via !".

which means, set -e does not work under the following simple cases (detailed explanations can be found on the wiki)

  1. Using the arithmetic operator let or $((..)) ( bash 4.1 onwards) to increment a variable value as

    #!/usr/bin/env bash
    set -e
    i=0
    let i++                   # or ((i++)) on bash 4.1 or later
    echo "i is $i" 
    
  2. If the offending command is not part of the last command executed via && or ||. For e.g. the below trap wouldn't fire when its expected to

    #!/usr/bin/env bash
    set -e
    test -d nosuchdir && echo no dir
    echo survived
    
  3. When used incorrectly in an if statement as, the exit code of the if statement is the exit code of the last executed command. In the example below the last executed command was echo which wouldn't fire the trap, even though the test -d failed

    #!/usr/bin/env bash
    set -e
    f() { if test -d nosuchdir; then echo no dir; fi; }
    f 
    echo survived
    
  4. When used with command-substitution, they are ignored, unless inherit_errexit is set with bash 4.4

    #!/usr/bin/env bash
    set -e
    foo=$(expr 1-1; true)
    echo survived
    
  5. when you use commands that look like assignments but aren't, such as export, declare, typeset or local. Here the function call to f will not exit as local has swept the error code that was set previously.

    set -e
    f() { local var=$(somecommand that fails); }        
    g() { local var; var=$(somecommand that fails); }
    
  6. When used in a pipeline, and the offending command is not part of the last command. For e.g. the below command would still go through. One options is to enable pipefail by returning the exit code of the first failed process:

    set -e
    somecommand that fails | cat -
    echo survived
    

The ideal recommendation is to not use set -e and implement an own version of error checking instead. More information on implementing custom error handling on one of my answers to Raise error in a Bash script

참고URL : https://stackoverflow.com/questions/2870992/automatic-exit-from-bash-shell-script-on-error

반응형