쉘 스크립트의 한 부분이 실패하면 어떻게 종료합니까?


51

쉘 스크립트의 일부가 실패 할 경우 종료하는 쉘 스크립트를 작성하려면 어떻게해야합니까? 예를 들어, 다음 코드 스 니펫이 실패하면 스크립트가 종료됩니다.

n=0
until [ $n -ge 5 ]
do
  gksu *command* && break
  n=$[$n+1]
  sleep 3

답변:


88

한 가지 방법은 set -e스크립트의 시작 부분에 추가 하는 것 입니다. 그 의미는 (에서 help set) :

  -e  Exit immediately if a command exits with a non-zero status.

따라서 명령 중 하나라도 실패하면 스크립트가 종료됩니다.

또는 exit가능한 실패 지점에서 명시 적 명령문을 추가 할 수 있습니다 .

command || exit 1

5
나는 (그리고 bash wiki ) 오히려 사람들은 (디자인 IMO) set -e기능을 사용하는 대신 적절한 오류 처리에 대해 생각할 것 입니다. 여기에는 실제로 적용되지 않습니다. OP는 명령 실행을 5 회 실패한 후 스크립트를 종료하려고합니다.
Stéphane Chazelas

1
@ StéphaneChazelas 그것이 깨 졌는지 여부에 대해 당신과 논쟁하지 않을 것입니다, 당신이 옳습니다. 그러나 OP는 "일부 오류가 발생하면 종료하는 쉘 스크립트를 작성하려면 어떻게해야합니까?"라고 물었습니다. 5 번의 실패 후 종료에 대해 어떻게 생각하십니까?
terdon

질문을 해석 할 수있는 다른 방법을 생각할 수 없기 때문입니다.
Stéphane Chazelas

1
@ StéphaneChazelas 당신이 옳을 수도 있습니다. 나는 그것을 문자 그대로 해석했습니다 : 스크립트의 일부가 실패하면 전체 스크립트가 어떻게 종료 될 수 있습니까? 그리고 set -e내가 아는 유일한 방법입니다.
terdon

이 스크립트 snipet에서 실행할 수있는 명령 set -e입니다 sleep( break특수 내장되는이 스크립트는 대부분의 쉘에서 실패 종료 원인이에 명령 if또는 왼쪽에 &&영향을받지 않습니다 set -e, n=...경우 실패 할 수 n읽기 전용,하지만입니다 그없이 스크립트 종료 것 set -e그 해석이 꽤 가능성이 소리 때문에)도 있습니다. 나는 그 질문이 잘못되었다는 데 동의합니다.
Stéphane Chazelas

17

키워드를 사용하여 어느 곳에서나 스크립트를 종료 할 수 있습니다 exit. 또한 또는 스크립트가, 예를 들어 실패하는 방법을 다른 프로그램에 표시하기 위해 종료 코드를 지정할 수 있습니다 exit 1또는 exit 2관례 등 (종료 코드 0은 성공 0 실패 의미보다 더 큰 것을위한 것입니다하지만, 또한 대회 종료에 의해 127 이상의 코드는 비정상적으로 종료되도록 예약되어 있습니다 (예 : 신호).

실패시 종료되는 일반적인 구조는

if [ failure condition ]; then
    exit n
fi

적합 failure condition하고 n. 그러나 특정 시나리오에서는 다르게 진행될 수 있습니다. 이제 귀하의 경우 다섯 번의 호출 중 하나라도 gksu실패하면 종료한다는 의미로 귀하의 질문을 해석합니다 . 한 가지 방법은 다음과 같은 기능을 사용하는 것입니다

function try_command {
    for i in 1 2 3 4 5 ; do
        if gksu command ; then
            return 0
        fi
    fi
    exit 1
}

그런 다음을 사용하여 루프를 호출하십시오 try_command.

질문을 해결하는 방법에는 고급 또는 정교한 방법이 있습니다. 그러나 위의 솔루션은 Stephane의 솔루션보다 초보자가 더 쉽게 액세스 할 수 있습니다.


10
attempt=0
until gksu command; do
  attempt=$((attempt + 1))
  if [ "$attempt" -gt 5 ]; then
    exit 1
  fi
done

exit서브 쉘에서 호출되지 않는 한 스크립트를 종료합니다. 예를 들어, 스크립트가 파이프 라인 내에 (...)있거나 $(...)파이프 라인의 일부 이기 때문에 스크립트의 해당 부분이 서브 쉘에있는 경우 해당 서브 쉘 만 종료됩니다 .

이 경우 서브 쉘 외에 스크립트 를 종료하려면 해당 서브 exit쉘 종료 를 호출해야합니다 .

예를 들어, 여기에 2 개의 중첩 레벨 서브 쉘이 있습니다.

(
  life=hard
  output=$(
    echo blah
    [ "$life" = easy ] || exit 1 # exit subshell
    echo blih not run
  ) || exit # if the subshell exits with a non-zero exit status,
            # exit as well with the same exit status

  echo not run either
) || exit # if the subshell exits with a non-zero exit status,
          # exit as well with the same exit status

서브 쉘이 파이프 라인의 일부이면 까다로울 수 있습니다. bash특별한이 $PIPESTATUS유사 배열 zsh의의 ' $pipestatus여기에 당신을 도울 수 하나를 :

{
   echo foo
   exit 1
   echo bar
} | wc -c
subshell_ret=${PIPESTATUS[0]}
if [ "$subshell_ret" -ne 0 ]; then
  exit "$subshell_ret"
fi

3

트랩은 신호를 받으면 조치를 수행합니다.

trap "echo EXIT;  exit" 0
trap "echo HUP;   exit" 1
trap "echo CTL-C; exit" 2
trap "echo QUIT;  exit" 3
trap "echo ERR;   exit" ERR
n=0
until [ $n -ge 5 ]
do
  n=$[$n+1]
  echo $n
  sleep 3
done

이것을 실행하고 정상적으로 종료하십시오. 신호 0을 트랩합니다.

EXIT

다시 실행하고 ^ C로 인터럽트하십시오. 신호 2와 신호 0을 모두 트랩합니다.

CTL-C
EXIT

0이 아닌 종료 상태는 ERR에서 트랩됩니다.

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