for 루프의 결과에 따라이 스크립트를 오류 엑시트로 만들려면 어떻게해야합니까?


13

set -o errexit오류가 발생하면 전체 스크립트가 실패 시점에 종료되도록 사용하는 bash 스크립트 가 있습니다.
스크립트는 curl의도 한 파일을 검색하지 못하는 명령을 실행 하지만,이 경우 스크립트는 오류 종료에 실패하지 않습니다.

for루프를 추가했습니다

  1. 몇 초 동안 일시 중지 한 후 curl명령 을 다시 시도하십시오.
  2. 사용 false기본 0이 아닌 종료 상태를 정의하는 for 루프의 맨 아래에 - 컬 명령이 성공하면 - 루프 휴식과 마지막 명령의 종료 상태를 0이어야합니다.
#! /bin/bash

set -o errexit

# ...

for (( i=1; i<5; i++ ))
do
    echo "attempt number: "$i
    curl -LSso ~/.vim/autoload/pathogen.vim https://tpo.pe/pathogen.vim
    if [ -f ~/.vim/autoload/pathogen.vim ]
    then
        echo "file has been retrieved by curl, so breaking now..."
        break;
    fi

    echo "curl'ed file doesn't yet exist, so now will wait 5 seconds and retry"
    sleep 5
    # exit with non-zero status so main script will errexit
    false

done

# rest of script .....

문제는 curl명령이 실패 할 때 루프가 명령을 다섯 번 재 시도하는 것입니다. 모든 시도가 실패하면 for 루프가 완료되고 기본 스크립트가 재개됩니다 errexit.
curl문이 실패하면 전체 스크립트를 종료하려면 어떻게해야합니까?

답변:


18

바꾸다:

done

와:

done || exit 1

for루프가 0이 아닌 종료 코드로 종료되면 코드가 종료됩니다 .

사소한 점으로 1in exit 1은 필요하지 않습니다. 일반 exit명령은 false다운로드에 실패하면 마지막으로 실행 된 명령의 종료 상태 ((코드 = 1))로 종료됩니다. 다운로드가 성공하면 루프의 종료 코드는 echo명령 의 종료 코드입니다 . echo일반적으로 code = 0으로 종료합니다. 이 경우 ||에는 트리거되지 않으며 exit명령이 실행되지 않습니다.

마지막으로 set -o errexit놀라움으로 가득 차 있습니다. 장단점에 대한 논의는 Greg의 FAQ # 105를 참조하십시오 .

선적 서류 비치

보낸 사람 man bash:

for ((expr1; expr2; expr3)); 목록을; 완료
먼저 산술 표현식은 expr1 규칙 산술 EVALUATION 아래 설명에 따라 평가된다. 그런 다음 산술 표현식 expr2는 0으로 평가 될 때까지 반복적으로 평가됩니다. expr2가 0이 아닌 값으로 평가 될 때마다 목록이 실행되고 산술 표현식 expr3이 평가됩니다. 표현식이 생략되면 1로 평가되는 것처럼 작동합니다. 리턴 값은 실행 된 list에서 마지막 명령의 종료 상태이거나 표현식이 유효하지 않은 경우 false입니다. [엠파 시스 추가]


truebreak 문 앞에 명시 적으로 명시하고 루프의 종료 값을 확보 하는 것이 좋은 생각이라고 생각하십니까 ?
RobertL

1
나는 명시 적이 암시 적보다 낫다고 생각합니다 . 그렇기 때문에 나는 exit 1평범한 exit일이 일어 났을 때 썼다 . 그러나 스타일에 관한 문제이며 다른 사람들은 자신의 의견을 가질 수 있습니다.
John1024

1
잘 작동합니다! 고마워 :) 개인적으로 나는 exit일반 종료로 읽을 것입니다 -스크립트 자체가 종료됩니다. exit 1 다른 프로세스에 대한 "신호"로 읽습니다. 즉 errexit, "결과"에 따라 스크립트를 종료해야합니다 exit 1. -그래서 나는 함께 exit갔지만 설명해 주셔서 감사합니다
the_velour_fog

1
오류 조건으로 인해 스크립트가 종료되면을 호출 해야 합니다 exit 1. 그것은 전혀 영향 errexit을 미치지 않습니다 . 호출 프로그램에 문제가 있음을 알려줍니다. 이 false명령에는 하나의 명령문이 exit(1)있습니다. 유닉스 명령어의 99.9 %가 성공하면 0을, 에러는 0이 아닌 값을 반환합니다. 당신도 그래야합니다.
RobertL

2

당신이 경우 errexit설정, 다음 false문은 즉시 종료에 스크립트를 야기한다. curl명령이 실패한 경우에도 마찬가지입니다.

errexit가 설정된 경우 curl처음 호출 false할 때 첫 번째 명령이 실패한 후 작성된 스크립트의 예제 스크립트 입니다.

작동 방식을 확인하려면 (약칭 -e을 사용하여 설정하십시오 errexit.

$ ( set -e;  false; echo still here )
$

$ ( set +e;  false; echo still here )
still here
$

따라서 curl명령이 두 번 이상 실행되면이 스크립트가 errexit설정 되지 않은 것 입니다.


1
set -e그보다 더 미묘합니다. 그것은 것입니다 하지 루프의 첫 번째 실패 명령 후 종료합니다. (set -e; for (( i=1; i<5; i++ )); do echo $i; false; done || echo "FAIL"; )코드를 false4 번 실행 하고 실행하여 자신에게이를 증명할 수 있습니다 . 에 대한 자세한 내용 set -eGreg의 FAQ # 105를 참조하십시오 .
John1024

@ John1024 감사합니다. 이것은 아래로 내려 가고 있습니다.
RobertL

@ John1024 그러나 증거가 아직 errexit설정되지 않은 것 같습니다. 문제의 스크립트에 논리를 적용하십시오. 이것을 실행하십시오 : (set -e; for (( i=1; i<5; i++ )); do echo $i; false; done ; echo still here )if while || &&etc로 리턴 값을 테스트 해도 오류가 발생하지 않습니다. 원래 스크립트는 ||for 루프 가 아닙니다 .
RobertL

방금 set -o errexit예제 코드에 명령을 표시하지 않았 으며 지금 추가 한 것으로 나타났습니다 . 예상대로 오류가 종료되지 않았습니다. 나는 falsefor 루프에서 마지막 명령 으로 유지하고 루프를 닫을 필요가 있었다 done || exit [1].
the_velour_fog

@RobertL 나는 당신의 요점을 참조하십시오.
John1024

1

set -o errexit 프로세스에서 빠져 나가야하기 때문에 루프와 서브 쉘에서 까다로울 수 있습니다.

루프를 끊는 것은 (정상적인 작동 중에도) 나쁜 습관으로 간주됩니다. 두 가지 조건에서 for-loop보다는 while-loop를 선호하도록 old-school을 호출 할 수는 있지만 읽는 것이 더 좋습니다.

i=1
RET=-1
while [ $i -le 5 ] && [ $RET -ne 0 ]; do
    [ $i -eq 1 ] || sleep 5
    echo "attempt number: "$i
    curl -LSso ~/.vim/autoload/pathogen.vim https://tpo.pe/pathogen.vim
    RET=$?
    i=$((i+1))
done
exit $RET

0

경우는 errexit설정하고있다 curl명령은 바로 실패 컬 명령 후 스크립트 종료를 실패합니다. bash 매뉴얼에는 set -e복합 명령에서 단일의 실패한 리턴 상태 를 무시하는 힌트가 없습니다 . 복합 명령 set -e이 무시 되는 컨텍스트에서 실행되는 경우에만 해당됩니다 .
https://www.gnu.org/software/bash/manual/bash.html#The-Set-Builtin

RobertL이 게시 한 약간 수정 된 예제를 사용해보십시오. 이것은 false 명령 바로 다음의 첫 번째 반복에서 중지됩니다.

( set -e; for (( i=1; i<5; i++ )); do echo $i; false; echo "${i}. iteration done"; done ; echo "loop done" )

0

curl 명령에 --fail 옵션을 추가하면 문제가 해결되며, curl 명령이 실패하면 스크립트가 실패하고 오류가 발생하면 jenkins pipeline에서 curl을 사용할 때 매우 유용합니다.

curl -LSso --fail ~/.vim/autoload/pathogen.vim https://tpo.pe/pathogen.vim
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.