명령 오류에서 bash 스크립트 자동 실행 기능을 사용할 수 있습니까?


12

많은 명령을 수행 해야하는 쉘 스크립트를 작성 중이며 모든 명령은 모든 이전 명령에 따라 다릅니다. 명령이 실패하면 전체 스크립트가 실패하고 종료 함수를 호출합니다. 각 명령의 종료 코드를 확인할 수는 있지만 활성화 할 수있는 모드가 있거나 bash가 자동으로 수행 할 수있는 방법이 있는지 궁금합니다.

예를 들어 다음 명령을 사용하십시오.

cd foo || myfunc
rm a || myfunc
cd bar || myfunc
rm b || myfunc


이 명령을 실행하기 전에 쉘에 신호를 보내어 myfunc을 호출 해야하는 방법이 있습니까?

cd foo
rm a
cd bar
rm b

답변:


13

bash trap ERR 을 사용하면 명령이 상태가 0보다 큰 경우 스크립트를 종료하고 종료시 함수를 실행할 수 있습니다.

다음과 같은 것 :

myfunc() {
  echo 'Error raised. Exiting!'
}

trap 'myfunc' ERR

# file does not exist, causing error
ls asd
echo 123

참고 것을 bash는 트랩은 ERR 암시 적 수행 set -o errexit또는 set -e및 POSIX 없습니다.

그리고 ERR트랩은 실패한 명령은 즉시 다음 명령 목록의 일부인 경우 실행되지 않습니다 until또는 while키워드, 다음 시험의 일부 if또는 elif예약어는 명령의 일부에서 실행 &&또는 ||목록, 또는 명령의 반환 상태가 사용 반전되는 경우 !.


1

허용 된 답변에 대한 (아마도) 간단한 변형 :

  1. 사용 set -e 목록의 실행을 중단하는 하나 개의 명령의 오류가 발생할 수 있습니다.
  2. 명령을 간단히 나열하십시오.
  3. 사용 if- then- else오류 처리 명령 (들)을 실행하기 위해 문을. 이 마지막 조각은 약간 까다 롭습니다. 손목 시계:
세트 -e
만약
    cmd 1                         # 예 : cd foo
     cmd 2                         # 예 : rm a
     cmd 3                         # 예 : cd bar
     cmd 4                         # 예 : rm b
그때
    + e 설정
    성공시 수행 할 명령 (있는 경우)
그밖에
    + e 설정
    myfunc
    실패시 수행 할 다른 명령 (있는 경우) 
fi

까다로운 부분은 당신이 당신의 명령을 넣어 것입니다 으로 부분ifif- then- else가 아닌 then일부 또는 else부분. 리콜 의 구문 if 이다

 목록 이면 ; 그런 다음  목록 ; [elif  list ; 그런 다음  목록 ; ] ... [else  list ; ] fi 
   ↑↑↑↑
set -e경우, 쉘 알려줍니다 (가 ) 실패가 계속 안 및 실행 ( 등 라인 아래에 참조). 이것이 쉘 스크립트의 가장 바깥 레벨에서 명령이 발생하면 쉘이 종료됩니다. 그러나 · · · 는 다음에 오는 (복합) 목록 이므로이 네 가지 명령 중 하나라도 실패하면 전체 목록이 실패하여 절이 실행됩니다. 네 개의 명령이 모두 성공하면 절이 실행됩니다.cmd1cd foocmd2rm acmd1cmd2cmd3cmd4ifelsethen

두 경우 모두 가장 먼저해야 할 일은을 수행하여 e옵션 을 비활성화 (끄기)하는 것 set +e입니다. 그렇지 않으면 명령이 myfunc실패하면 스크립트가 물에서 날아갈 수 있습니다 .

set -e되고 지정되고 POSIX 명세서에 기재된 .


0

" 모든 명령은 모든 이전 명령에 의존합니다. 모든 명령이 실패하면 전체 스크립트가 실패해야합니다 "라는 말을 들었습니다. 오류를 처리하기 위해 특별한 기능이 필요하지 않다고 생각합니다.

필요한 것은 &&오퍼레이터 및 ||연산자 와 명령을 연결 하는 것입니다.

예를 들어,이 체인은 끊어지고 이전 명령 하나 라도 끊어지면 "뭔가 잘못되었습니다"를 인쇄 합니다 (bash는 왼쪽에서 오른쪽으로 읽습니다)

cd foo && rm a && cd bar && rm b || echo "something went wrong"

실제 예 (실제 데모 용으로 dir foo, file a, dir bar 및 file b를 만들었습니다) :

gv@debian:/home/gv/Desktop/PythonTests$ cd foo && rm a && cd bar && rm bb || echo "something is wrong"
rm: cannot remove 'bb': No such file or directory
something is wrong #mind the error in the last command

gv@debian:/home/gv/Desktop/PythonTests$ cd foo && rm aa && cd bar && rm b || echo "something is wrong"
rm: cannot remove 'aa': No such file or directory
something is wrong #mind the error in second command in the row

마지막으로 모든 명령이 성공적으로 실행되면 (종료 코드 0) 스크립트는 계속 진행됩니다.

gv@debian:/home/gv/Desktop/PythonTests$ cd foo && rm a && cd bar && rm b || echo "something is wrong"
gv@debian:/home/gv/Desktop/PythonTests/foo/bar$ 
# mind that the error message is not printed since all commands were successful.

기억해야 할 것은 &&를 사용하면 이전 명령이 코드 0으로 종료되면 bash의 경우 성공을 의미합니다.

체인에서 명령이 잘못되면 명령 / 스크립트 / 다음에 오는 것이 무엇이든 || 실행됩니다.

그리고 기록을 위해, 파산 한 명령에 따라 다른 작업을 수행 해야하는 경우 $?정확히 이전 명령의 종료 코드를보고하는 값을 모니터링하여 클래식 스크립트로 수행 할 수도 있습니다 (명령이 성공적으로 실행되면 0을 반환 함) 또는 명령이 실패한 경우 다른 양수)

예:

for comm in {"cd foo","rm a","cd bbar","rm b"};do  #mind the error in third command
eval $comm
    if [[ $? -ne 0 ]];then 
        echo "something is wrong in command $comm"
        break
    else 
    echo "command $comm executed succesful"
    fi
done

산출:

command cd foo executed succesfull
command rm a executed succesfull
bash: cd: bbar: No such file or directory
something is wrong in command cd bbar

팁 : "bash : cd : bbar : No such file ..."메시지를 적용하여 억제 할 수 있습니다. eval $comm 2>/dev/null

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.