명령이 실패한 경우 종료하는 방법?


222

나는 쉘 스크립팅의 멍청한 놈입니다. 명령이 실패하면 메시지를 인쇄하고 스크립트를 종료하고 싶습니다. 난 노력 했어:

my_command && (echo 'my_command failed; exit)

그러나 작동하지 않습니다. 스크립트에서이 줄 다음에 나오는 지침을 계속 실행합니다. 우분투와 bash를 사용하고 있습니다.


5
닫히지 않은 따옴표가 실패 / 종료를 유발하는 구문 오류가되도록 하시겠습니까? 그렇지 않은 경우 예제에서 따옴표를 닫아야합니다.
hobs

답변:


406

시험:

my_command || { echo 'my_command failed' ; exit 1; }

네 가지 변경 사항 :

  • 변경 &&||
  • { }대신 사용( )
  • ;후 소개exit
  • 후 구역 {및 이전}

당신이 메시지와 명령 (아닌 값으로 종료) 실패 할 경우에만 종료를 인쇄 할 때문에 당신은 필요가 ||아닌를 &&.

cmd1 && cmd2

성공하면 실행 cmd2됩니다 cmd1(exit value 0). 어디로

cmd1 || cmd2

실패하면 실행 cmd2됩니다 cmd1(종료 값이 0이 아님).

를 사용 ( )하면 내부 명령이 하위 셸 에서 실행되고 exit거기에서 a 를 호출하면 원래 셸이 아닌 하위 셸이 종료되므로 원래 셸에서 계속 실행됩니다.

이 사용을 극복하기 위해 { }

마지막 두 가지 변경 사항은 bash에 필요합니다.


4
"역전 된"것으로 보입니다. 함수가 "성공"하면 0을 반환하고 "실패"하면 0이 아닌 값을 반환하므로 &&는 전반이 0이 아닌 값을 반환 한시기를 평가할 수 있습니다. 그렇다고 위의 답변이 잘못되었다는 의미는 아닙니다. && 및 || 스크립트에서 반환 값이 아닌 성공을 기반으로 작동합니다.
CashCow

7
역순으로 보이지만 읽어 보면 "이 명령을 성공적으로 수행합니다"또는 "이 오류를 인쇄하고 종료합니다"
simpleuser

2
그 배후의 논리는 언어가 단락 평가 (SCE)를 사용한다는 것입니다. SCE에서 f는 "p OR q"형식이며 p는 true로 평가되므로 q를 볼 이유가 없습니다. 식이 "p AND q"형식이고 p가 false로 평가되면 q를 볼 이유가 없습니다. 그 이유는 두 가지입니다. 1) 명백하고 빠른 이유 2) SCE가 없으면 "if x! = 0 AND 10 / x> 5"와 같은 특정 종류의 오류를 피합니다. ). 이와 같은 명령 줄에서이 기능을 사용하는 것은 행복한 부작용입니다.
user2635263

2
나는 STDERR에 반향하는 것이 좋습니다 것입니다 :{ (>&2 echo 'my_command failed') ; exit 1; }
rynop

127

다른 답변은 직접 질문을 잘 다루었지만을 사용하는 데 관심이있을 수 있습니다 set -e. 이를 통해 if테스트 와 같은 특정 컨텍스트 이외의 명령이 실패 하면 스크립트가 중단됩니다. 특정 스크립트의 경우 매우 유용합니다.


3
불행히도, 그것은 또한 매우 위험합니다- set -e그것이 작동하는 시간과 작동하지 않는 시간에 대한 길고 비전적인 규칙을 가지고 있습니다. (사람이 실행되면 if yourfunction; then ..., 다음 set -e화재 내부 결코 yourfunction그 코드를 고려하거나 호출 무엇 때문에 "확인"). BashFAQ # 105의 연습 섹션을 참조 하여 이것과 다른 함정에 대해 논의하십시오 (일부는 특정 쉘 버전에만 적용되므로 스크립트를 실행하는 데 사용할 수있는 모든 릴리스에 대해 테스트해야합니다).
Charles Duffy

67

또한 각 명령의 종료 상태는 셸 변수 $?에 저장되며 명령 실행 후 즉시 확인할 수 있습니다. 0이 아닌 상태는 실패를 나타냅니다.

my_command
if [ $? -eq 0 ]
then
    echo "it worked"
else
    echo "it failed"
fi

10
my_command 인 경우, 대신 test 명령을 사용할 필요가 없습니다.
Bart Sas

5
+1 나는 당신이이 대안을 열거 한 것에 대해 처벌받지 말아야한다고 생각하기 때문에-그것은 테이블에 있어야합니다. 난 그냥 바보).
Tony Delroy

1
@BartSas 명령이 길면 자체 줄에 입력하는 것이 좋습니다. 스크립트를 더 읽기 쉽게 만듭니다.
Michael

@Michael, 라인 B에 대해 이해하기 전에 라인 A에서 발생한 일을 알아야하는 경우 (또는 라인 B에서 발생하는 상황을 알아야 함) 줄 A의 끝에 새로운)). 내가 너무 많은 시간을 누군가가 추가 본 적이 echo "Just finished step A"그 것을 모르고 echo덮어 $?가는 나중에 검사 할 수 있습니다.
Charles Duffy

67

스크립트의 모든 명령에 대해 해당 동작을 원하면 추가하십시오.

  set -e 
  set -o pipefail

스크립트의 시작 부분에. 이 옵션 쌍은 명령이 0이 아닌 종료 코드와 함께 리턴 될 때마다 bash 인터프리터에게 종료하도록 지시합니다.

그래도 종료 메시지를 인쇄 할 수 없습니다.


8
trapbash 내장 명령을 사용하여 종료시 명령을 실행할 수 있습니다 .
Gavin Smith

이것이 XY 질문에 대한 답변입니다.
jwg

5
쌍이 아닌 독립적으로 수행되는 명령을 설명하는 것이 흥미로울 수 있습니다. 특히 set -o pipefail원하는 동작이 아닐 수 있습니다. 지적 해 주셔서 감사합니다!
Antoine Pinsard

3
set -e전혀 신뢰할 수 있고 일관성이 있거나 예측할 수있는 것은 아닙니다! 이를 확인하려면 BashFAQ # 105 의 연습 섹션 또는 in-ulm.de/~mascheck/various/set-e
Charles Duffy

14

다음 관용구를 해킹했습니다.

echo "Generating from IDL..."
idlj -fclient -td java/src echo.idl
if [ $? -ne 0 ]; then { echo "Failed, aborting." ; exit 1; } fi

echo "Compiling classes..."
javac *java
if [ $? -ne 0 ]; then { echo "Failed, aborting." ; exit 1; } fi

echo "Done."

각 명령 앞에 정보 에코를 사용하고 각 명령 뒤에 동일한
if [ $? -ne 0 ];...행을 사용하십시오. 물론 원하는 경우 해당 오류 메시지를 편집 할 수 있습니다.


이를 함수로 정의하여 재사용 할 수 있습니다.
Eric Wang

1
'만약 [$? -ne0]; 그러면 ... fi '는'|| '를 작성하는 복잡한 방법입니다.
kevin cline

if ! javac *.java; then ...-왜 $?전혀 귀찮게 ?
Charles Duffy

찰스-나는 평범한 배쉬 스크립터이기 때문에 :)
Grant Birchmeier

10

제공은 my_commandcanonically, 설계 즉, 성공하면 그 다음, 0을 반환 &&정확하게 당신이 원하는 것을 반대입니다. 당신은 원합니다 ||.

또한 (bash에서 나에게 옳지 않은 것처럼 보이지만 현재 위치에서 시도 할 수는 없습니다. 말해.

my_command || {
    echo 'my_command failed' ;
    exit 1; 
}

IIRC, 당신은 내부의 각 라인 {} 이후에 세미콜론이 필요
알렉스 Howansky

9
@Alex : 별도의 줄에 있지 않은 경우.
추후 공지가있을 때까지 일시 중지되었습니다.

5

종료 오류 상태를 유지하고 한 줄에 하나의 명령으로 읽을 수있는 파일이있는 경우에도 사용할 수 있습니다.

my_command1 || exit $?
my_command2 || exit $?

그러나 추가 오류 메시지는 인쇄되지 않습니다. 그러나 어떤 경우에는 실패한 명령으로 오류가 인쇄됩니다.


1
그럴 이유가 없습니다 exit $?. 단지 exit사용하는 $?기본 값으로.
Charles Duffy

@CharlesDuffy는 몰랐다. 굉장히 더 간단합니다!
alexpirine

3

trap쉘 내부 명령 (즉, 0이 아닌 리턴 상태) 실패 명령 실행을 포함 잡기 신호 및 기타 유용한 조건을 수 있습니다. 따라서 모든 단일 명령의 반환 상태를 명시 적으로 테스트하지 않으려면 명령이 trap "your shell code" ERR0이 아닌 상태를 반환 할 때마다 쉘 코드가 실행됩니다. 예를 들면 다음과 같습니다.

trap "echo script failed; exit 1" ERR

실패한 명령을 잡는 다른 경우와 마찬가지로 파이프 라인에는 특별한 처리가 필요합니다. 위는 잡을 수 없습니다 false | true.

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