쉘 스크립트의 종료 상태에 "예약 된"코드 사용


15

최근 에 고급 Bash 스크립팅 안내서 에서이 특수한 의미가진 종료 코드 목록을 발견했습니다 . 이들은이 코드를 예약 된 것으로 참조하고 다음을 권장합니다.

위의 표에 따르면, 종료 코드 1-2, 126-165 및 255는 특별한 의미를 가지므로 사용자 지정 종료 매개 변수에 대해서는 피해야합니다.

얼마 전에 다음과 같은 종료 상태 코드를 사용하는 스크립트를 작성했습니다.

  • 0-성공
  • 1-잘못된 호스트 이름
  • 2-잘못된 인수가 지정되었습니다
  • 3-불충분 한 사용자 권한

스크립트를 작성할 때 특수 종료 코드를 알지 못했기 때문에 첫 번째 오류 조건에 대해 1에서 시작하여 각 연속 오류 유형에 대해 종료 상태를 증가 시켰습니다.

나는 나중 단계에서 다른 스크립트 (0이 아닌 종료 코드를 확인할 수 있음)에 의해 호출 될 수 있도록 스크립트를 작성했습니다. 나는 실제로 그것을 아직하지 않았다. 지금까지 대화 형 셸 (Bash)에서만 스크립트를 실행했으며 사용자 정의 종료 코드를 사용하여 어떤 문제가 발생할 수 있는지 궁금합니다. Advanced Bash-Scripting Guide의 권장 사항은 어느 정도 중요합니까?

Bash 문서에서 확실한 조언을 찾을 수 없었습니다. 종료 상태 섹션 에는 Bash가 사용하는 종료 코드가 나열되어 있지만 이들 중 어느 것도 자신의 스크립트 / 프로그램에 사용하도록 예약 또는 경고 되어 있지는 않습니다 .


6
나와 다른 사람들은 ABSG가 일반적으로 품질이 낮다고 생각합니다. 내 의견으로는 링크 한 페이지의 저자는 나열된 종료 코드가 쉘 자체가 특정 의미로 사용한다는 사실에 근거하여 나열된 종료 코드가 예약되어 있다고 주장하지 않습니다. 스크립트에 대한 표준을 만들려는 시도가 있었지만 어느 것도 성공하지 못했습니다. 중요한 것은 선택한 오류 코드를 문서화하여 스크립트 소비자 (예 : 다른 스크립트)가 스크립트를 기반으로 수행 할 작업을 알 수 있도록하는 것입니다.
추후 공지가있을 때까지 일시 중지되었습니다.

@DennisWilliamson 댓글로 답변을 올리면 기꺼이 의견을 보내겠습니다. 나는 다른 답변들 모두가 유용하다는 것을 알았을 때 이미 다른 모든 답변에 투표했습니다. 귀하의 답변은 David King (및 Zwol의 답변)과 내용이 비슷하지만 ABSG 인용에 주장에 대한 증거는 없다고 명시 적으로 진술합니다.
Anthony G-

1
제안에 감사하지만 내 의견은 그대로 있어야한다고 생각합니다.
추후 공지가있을 때까지 일시 중지되었습니다.

그 후 POSIX 사양에 비슷한 조언이 포함되어 있음을 알았으므로 해당 정보를 내 답변에 추가했습니다 (이 질문을 한 이후 연구 결과가 포함되어 있음).
Anthony G-Monica에 대한 정의

답변:


10

프로세스 종료 코드의 의미를 표준화하려는 여러 시도가있었습니다. 언급 한 것 외에도 다음을 알고 있습니다.

  • BSD는 sysexits.h64 이상의 값에 대한 의미를 정의합니다.

  • grep코드 0을 종료하는 GNU 문서는 하나 이상의 일치 항목이 발견되었고 1은 일치 항목이 없음을 의미하고 2는 I / O 오류가 발생했음을 의미합니다. 이 규칙은 "아무것도 없었지만 아무것도 찾지 못했습니다"와 "I / O 오류가 발생했습니다"라는 의미가있는 다른 프로그램에도 유용합니다.

  • C 라이브러리 함수의 많은 구현은 system종료 코드 127을 사용하여 프로그램이 존재하지 않거나 시작하지 못했음을 나타냅니다.

  • Windows에서는 NTSTATUS코드 (32 비트 숫자 공간 전체에 불편하게 흩어져 있음)가 종료 코드로 사용될 수 있으며, 특히 심각한 오작동 (예 :)으로 인해 프로세스가 종료되었음을 나타내는 코드가 종료 코드로 사용될 수 있습니다 STATUS_STACK_OVERFLOW.

이러한 규칙 중 하나를 준수하는 특정 프로그램을 신뢰할 수 없습니다. 신뢰할 수있는 유일한 규칙은 종료 코드 0이 성공이고 다른 것은 실패라는 것입니다. (C89의 값이 0 인 EXIT_SUCCESS것은 아닙니다 . 그러나 값이 같지 않아도 exit(0)동일하게 동작해야합니다 exit(EXIT_SUCCESS).)


감사. 다른 답변보다 하나의 답변을 선택하는 것이 어려웠지만 사용중인 다양한 종료 코드 (관련 링크 포함)의 다양한 풍미를 제공하면서 내 질문에 답변했기 때문에이 답변을 수락합니다. 현재 가지고 있습니다.
Anthony G-Monica에 대한 정의

11

없음 종료 코드는 특별한 의미가 없습니다 만,의 값은 $?특별한 의미를 가질 수있다.

Bourne Shell 및 ksh93이 종료 코드 및 오류 상황을 처리하고 쉘 변수 $?에 전달하는 방식이 문제입니다. 나열한 내용과 달리 다음 값만 $?특별한 의미를 갖습니다.

  • 126 바이너리가 존재하더라도 실행할 수 없습니다
  • 127 지정된 바이너리가 존재하지 않습니다
  • 128 종료 상태는 == 0이지만 지정되지 않은 문제가 있습니다.

또한 $?신호에 의해 중단 된 프로그램을 위해 예약 된 지정되지 않은 쉘 및 플랫폼 별 코드 범위 > 128이 있습니다.

  • Bourne Shell bash 및 ksh88은 128 + 신호 번호를 사용합니다.
  • ksh93은 256 + 신호 번호를 사용합니다.

다른 값은 쉘 특수 $?값 과 구별 될 수 있으므로 문제를 일으키지 않습니다 .

특히, 값 1과 2는 특수 조건에 사용되지 않고 내장 명령이 없을 때 동일하게 작동 할 수있는 내장 명령에 의해 사용되는 종료 코드 일뿐입니다. 따라서 제공 한 bash 스크립팅 안내서에 대한 포인터 는 특정 코드가 자체 스크립트에서 피해야하는 특수 값인지 여부를 언급하지 않고 bash에서 사용하는 코드를 나열하기 때문에 좋은 매뉴얼이 아닙니다.

Bourne Shell의 최신 버전은 프로그램이 종료 될 때까지 기다리지 waitid()않고 SVr4에 대해 1989 년에 도입되어 더 나은 syscall 인터페이스를 사용합니다 (1980 년 UNOS에서 이미 사용한 것과 유사).waitpid()waitid()

새로운 Bourne 쉘 버전은 인코딩으로 종료 이유 별도의 변수에 ${.sh.code}/ ${.sh.codename}종료 코드${.sh.status}/ ${.sh.termsig}, 참조 http://schillix.sourceforge.net/man/man1/bosh.1.html , 종료 코드에 과부하가되지 않습니다 특수 상태와`waitid () 사용의 결과로 Bourne Shell은 이제 하위 8 비트뿐만 아니라 종료 코드의 모든 32 비트 반환을 지원합니다.

BTW : exit(256)C 프로그램 또는 쉘 스크립트와 유사하거나 유사 하지 않도록주의하십시오 $?. 클래식 쉘에서는 0으로 해석됩니다.


2
BTW : waitid()5 월 말경 이 버그 에 대한 FreeBSD 및 Linux 커널에 대한 버그 보고서를 작성했습니다 . FreeBSD 사람들은 20 시간 안에 문제를 해결했고, Linux 사람들은 버그 수정에 관심이 없습니다. ... 그리고 Cygwin 사람들은 그들이 버그 리눅스 호환에 의해 버그라고 말합니다 ;-)
schily

2
이 동작은 단일 유닉스 사양에 필요합니다 . 예, 32 비트 값이 있지만이 값에는의 하위 8 비트 값을 포함하는 8 비트 비트 필드가 포함됩니다 _exit. 언급하고있는 FreeBSD 버그 보고서를 연결하십시오. 설명하고있는 문제를 오해하고있을 수 있습니다.
Random832

2
OP는 질문에 bash로 태그를 달고 질문 텍스트에 Bash를 언급했습니다. Bash는 Bourne 파생 쉘입니다. ${.sh.}변수를 지원하지 않습니다 . 그러나 "Bourne-derived"가 아니라 "Bourne"이라고 말하는 것은 사실입니다 (ksh93을 포함하더라도).
추후 공지가있을 때까지 일시 중지되었습니다.

2
이 답변은 SVR4 파생 Unix의 특정 변형에 매우 특정한 것으로 보입니다. V7에있는 것을 의미하지 않는 한 "휴대용 쉘 (Bourne shell)"과 같은 것은 없다는 점을 염두에두고 휴대용과 그렇지 않은 것에 대해 더 명확하게 알려주십시오.
zwol

4
반대로, 나는 여기서 변동 범위, 특히 역사적 변동을 과소 평가하는 것이 당신이라고 생각합니다. /bin/sh이러한 특수 종료 코드를 크로스 플랫폼으로 일관되게 작동시키는 데 의존하는 것처럼 들립니다 . (I는하지 않습니다 걱정 특정 시스템의 여부 /bin/sh"진짜 Bourne 쉘"라고 할 수 있습니다. 훨씬 더 중요한 것들의 대부분은 당신이 "진짜 유닉스 시스템"으로 인용 POSIX에서, 그 돈되는이 않는다는 것을 아는 것은 ' /bin/sh어쨌든 POSIX 호환을 제공 합니다.)
zwol

6

쉘 스크립팅의 경우, 때때로 이름이 sysexist.h붙은 쉘 예약 종료 코드 (접두사)와 동등한 쉘을 소스로 제공합니다.S_EX_exit.sh

기본적으로 다음과 같습니다.

EX_OK=0 # successful termination 
EX__BASE=64     # base value for error messages 
EX_USAGE=64     # command line usage error 
EX_DATAERR=65   # data format error 
EX_NOINPUT=66   # cannot open input 
EX_NOUSER=67    # addressee unknown 
EX_NOHOST=68    # host name unknown 
EX_UNAVAILABLE=69       # service unavailable 
EX_SOFTWARE=70  # internal software error 
EX_OSERR=71     # system error (e.g., can't fork) 
EX_OSFILE=72    # critical OS file missing 
EX_CANTCREAT=73 # can't create (user) output file 
EX_IOERR=74     # input/output error 
EX_TEMPFAIL=75  # temp failure; user is invited to retry 
EX_PROTOCOL=76  # remote error in protocol 
EX_NOPERM=77    # permission denied 
EX_CONFIG=78    # configuration error 
EX__MAX=78      # maximum listed value 

#System errors
S_EX_ANY=1      #Catchall for general errors
S_EX_SH=2       #Misuse of shell builtins (according to Bash documentation); seldom seen
S_EX_EXEC=126   #Command invoked cannot execute         Permission problem or command is not an executable
S_EX_NOENT=127  #"command not found"    illegal_command Possible problem with $PATH or a typo
S_EX_INVAL=128  #Invalid argument to exit       exit 3.14159    exit takes only integer args in the range 0 - 255 (see first footnote)                                                                                        
#128+n  Fatal error signal "n"  kill -9 $PPID of script $? returns 137 (128 + 9)                               
#255*   Exit status out of range        exit -1 exit takes only integer args in the range 0 - 255              
S_EX_HUP=129                                                                                                   
S_EX_INT=130   
#...

다음을 사용하여 생성 할 수 있습니다.

#!/bin/sh
src=/usr/include/sysexits.h
echo "# Generated from \"$src\"" 
echo "# Please inspect the source file for more detailed descriptions"
echo
< "$src" sed -rn 's/^#define  *(\w+)\s*(\d*)/\1=\2/p'| sed 's:/\*:#:; s:\*/::'
cat<<'EOF'

#System errors
S_EX_ANY=1  #Catchall for general errors
S_EX_SH=2   #Misuse of shell builtins (according to Bash documentation); seldom seen
S_EX_EXEC=126   #Command invoked cannot execute     Permission problem or command is not an executable
S_EX_NOENT=127  #"command not found"    illegal_command Possible problem with $PATH or a typo
S_EX_INVAL=128  #Invalid argument to exit   exit 3.14159    exit takes only integer args in the range 0 - 255 (see first footnote)
#128+n  Fatal error signal "n"  kill -9 $PPID of script $? returns 137 (128 + 9)
#255*   Exit status out of range    exit -1 exit takes only integer args in the range 0 - 255
EOF
$(which kill) -l |tr ' ' '\n'| awk '{ printf "S_EX_%s=%s\n", $0, 128+NR; }'

그래도 많이 사용하지는 않지만 오류 코드를 문자열 형식으로 뒤집는 셸 함수가 사용됩니다. 나는 그것을 명명했다 exit2str. 위의 exit.shgenerator 이름을 지정했다고 가정하면 ( )로 exit.sh.sh코드를 exit2str생성 할 수 있습니다 exit2str.sh.sh.

#!/bin/sh
echo '
exit2str(){
  case "$1" in'
./exit.sh.sh | sed -nEe's|^(S_)?EX_(([^_=]+_?)+)=([0-9]+).*|\4) echo "\1\2";;|p'
echo "
  esac
}"

PS1대화 형 셸 에서 이것을 사용하여 각 명령을 실행 한 후 종료 상태와 문자열 형식을 알 수 있습니다 (알려진 문자열 형식이있는 경우).

[15:58] pjump@laptop:~ 
(0=OK)$ 
[15:59] pjump@laptop:~ 
(0=OK)$ fdsaf
fdsaf: command not found
[15:59] pjump@laptop:~ 
(127=S_NOENT)$ sleep
sleep: missing operand
Try 'sleep --help' for more information.
[15:59] pjump@laptop:~ 
(1=S_ANY)$ sleep 100
^C
[15:59] pjump@laptop:~ 
(130=S_INT)$ sleep 100
^Z
[1]+  Stopped                 sleep 100
[15:59] pjump@laptop:~ 
(148=S_TSTP)$

이를 얻으려면 exit2str 함수에 대한 정보가 필요하지 않습니다.

$ ./exit2str.sh.sh > exit2str.sh #Place this somewhere in your PATH

그런 다음이를 사용 ~/.bashrc하여 각 명령 프롬프트에서 종료 코드를 저장 및 번역하고 프롬프트 ( PS1)를 표시하십시오 .

    # ...
    . exit2str.sh
PROMPT_COMMAND='lastStatus=$(st="$?"; echo -n "$st"; str=$(exit2str "$st") && echo "=$str"); # ...'
    PS1="$PS1"'\n($lastStatus)\$'
    # ...                                                                                   

일부 프로그램이 종료 코드 규칙을 따르는 방법을 관찰하고 일부 프로그램은 종료 코드 규칙에 대해 배우거나 더 쉽게 진행되는 것을 볼 수 있도록하는 데 매우 유용합니다. 한동안 사용해 본 결과, 많은 시스템 지향 쉘 스크립트가 규칙을 따릅니다. EX_USAGE다른 코드는 많지 않지만 특히 일반적입니다. $S_EX_ANY게으른 사람들을 위해 항상 (1) 있지만 (나는 하나입니다) 나는 때때로 규칙을 따르려고 노력합니다 .


오류 코드와 함께보고 된 오류로 인해 오류 종료가 발생하는 경우 사용할 오류 코드와 종료 코드 간의 맵핑과 같은 것이 있는지 궁금합니다. 합리적인 매핑을 만들어야 할 수도 있습니다.
PSkocik

1
와! 나는 그런 정교한 대답을 기대하지 않았습니다. 다른 명령이 어떻게 동작하는지 알 수있는 좋은 방법으로 시도해 보겠다. 감사.
Anthony G-Monica에 대한 정의

4

종료 코드를 문서화하여 돌아와서 스크립트를 조정해야 할 때부터 1 년 후를 기억하는 한 괜찮습니다. "예약 된 종료 코드"라는 아이디어는 0성공 코드 및 실패 코드로 사용 하는 것이 일반적이라고 말하는 것 외에는 더 이상 적용되지 않습니다 .


4

내가 찾을 수있는 가장 좋은 참조는 다음과 같습니다 : http://tldp.org/LDP/abs/html/exitcodes.html

이것에 따르면 :

1 오류에 대한 일반적인 포괄이며 항상 사용자 정의 오류에 사용되는 것을 보았습니다.

2 구문 오류와 같은 쉘 내장을 잘못 사용하기위한 것

귀하의 질문에 직접 대답하기 위해 예약 된 오류 코드를 사용하면 스크립트가 정상적으로 작동합니다. 오류 코드 = 1/2/3에 따라 오류를 처리한다고 가정하면 예상대로 작동합니다.

그러나 예약 된 오류 코드를 알고 사용하는 사람이 있으면 혼동 될 수 있습니다.

스크립트가 "뉴스가 좋지 않다"라는 Linux 규칙을 따르고 성공에 에코가 없다고 가정 할 때 오류가있는 경우 오류를 에코 한 다음 종료하는 것도 가능합니다.

if [ $? -ne 0 ];then
    echo "Error type"
    exit 1
fi

2

내가받은 답변 (다른 것들 중 하나를 선택하기가 어려웠습니다)에 따라 Bash가 사용하는 종료 코드를 사용하여 특정 유형의 오류를 나타내는 것은 해롭지 않습니다 . 사용자 스크립트가 이러한 오류 코드 중 하나로 종료되면 Bash (또는 다른 Unix 쉘)는 예외 처리기 실행과 같은 특별한 작업을 수행하지 않습니다.

고급 Bash 스크립팅 가이드의 저자가 종료 코드 (표준화하기 위해 BSD 시도에 동의 것으로 보인다 sysexits.h)과 단순히 추천 사용자가 쉘 스크립트를 작성할 때, 그들은 종료 코드를 지정하지 않는 것이 이미 사전 정의 된 종료 코드와 충돌 즉, 사용자 정의 종료 코드가 64-113 범위의 사용 가능한 50 개의 상태 코드로 제한됩니다.

아이디어 (및 이론적 근거)에 감사하지만 저자가 127의 인용 된 예와 같은 오류를 검사하는 경우를 제외하고는 조언을 무시하는 것이 해롭지 않다는 것이 더 명백한 경우 선호합니다. ( command not found).

관련 POSIX 사양

종료 코드에 대한 POSIX의 의견을 조사했으며 POSIX 사양은 Advanced Bash-Scripting Guide의 저자와 일치하는 것으로 보입니다. 관련 POSIX 사양 (강조 광산)을 인용했습니다.

명령 종료 상태

각 명령에는 다른 쉘 명령의 작동에 영향을 줄 수있는 종료 상태가 있습니다. 유틸리티가 아닌 명령의 종료 상태는이 섹션에 설명되어 있습니다. 표준 유틸리티의 종료 상태는 해당 섹션에 설명되어 있습니다.

명령을 찾을 수 없으면 종료 상태는 127입니다. 명령 이름을 찾았지만 실행 가능한 유틸리티가 아닌 경우 종료 상태는 126입니다. 쉘을 사용하지 않고 유틸리티를 호출하는 응용 프로그램은이 종료 상태 값을 사용해야합니다. 비슷한 오류를보고합니다.

단어 확장 또는 리디렉션 중에 명령이 실패하면 종료 상태는 0보다 커야합니다.

내부적으로 명령이 0이 아닌 종료 상태로 종료되는지 여부를 결정하기 위해 쉘은 시스템 인터페이스 볼륨에 정의 된 wait () 함수 WEXITSTATUS 매크로에 해당하는 명령에 대해 검색된 전체 상태 값을 인식해야합니다. POSIX.1-2008). 특수 매개 변수 '?'를 사용하여 종료 상태를보고 할 때 쉘은 사용 가능한 전체 8 비트의 종료 상태를보고해야합니다. 신호를 수신하여 종료 된 명령의 종료 상태는 128보다 큰 것으로보고됩니다.

exit유틸리티

다른 섹션에서 설명했듯이 특정 종료 상태 값은 특수 용도 로 예약되어 있으며 해당 용도로만 응용 프로그램에서 사용해야 합니다.

  • 126 – 실행할 파일을 찾았지만 실행 파일이 아닙니다.
  • 127 – 실행할 유틸리티를 찾을 수 없습니다.
  • >128 – 신호에 의해 명령이 중단되었습니다.

추가 정보

가치있는 것을 위해, 나는 특별한 의미를 가진 종료 코드 목록 중 하나를 제외한 모든 것을 확인할 수있었습니다 . 이 종료 코드 테이블은 Bash 참조에 설명 된 오류 코드 생성 방법에 대한 자세한 정보 및 예제를 제공하므로 유용합니다 .

128의 종료 상태 생성 시도

Bash 버전 3.2.25 및 4.2.46을 사용하여 128 Invalid argument to exit오류를 발생 시켰지만 255 (종료 상태가 범위를 벗어남)를 수신 할 때마다. 예를 들어, exit 3.14159쉘 스크립트 또는 대화식 자식 쉘의 일부로 실행되면 쉘은 255다음 코드로 종료됩니다 .

$ exit 3.14159
exit
bash: exit: 3.14159: numeric argument required

더 재미있게, 나는 또한 간단한 C 프로그램을 실행하려고 시도했지만 exit(3)이 경우 종료하기 전에 함수가 float를 int (이 경우 3)로 간단히 변환 한 것처럼 보입니다 .

#include <stdlib.h>
main()
{
    exit(3.14159);
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.