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

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

최근에 이 목록을 봤어요특별한 의미를 지닌 종료 코드고급 Bash 스크립팅 가이드에서 발췌. 그들은 이러한 코드를 호출합니다예약된그리고 다음을 권장합니다:

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

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

  • 0 - 성공
  • 1 - 잘못된 호스트 이름
  • 2 - 지정된 매개변수가 유효하지 않습니다.
  • 3 - 사용자 권한이 부족합니다.

스크립트를 작성할 때 특별한 종료 코드를 인식하지 못했기 때문에 첫 번째 오류 조건에 대해 1로 시작하고 연속되는 각 오류 유형에 대해 종료 상태를 증가시켰습니다.

나중에 다른 스크립트(0이 아닌 종료 코드를 확인할 수 있음)에서 호출할 수 있도록 이 스크립트를 작성했습니다. 저는 실제로 이 작업을 아직 수행하지 않았습니다. 지금까지는 대화형 셸(Bash)에서만 스크립트를 실행했으며 사용자 정의 종료 코드를 사용하는 데 문제가 있는지 궁금합니다. 고급 Bash 스크립팅 가이드의 조언은 얼마나 관련성이 있고 중요합니까?

Bash 문서 섹션에서 확인된 조언을 찾을 수 없습니다.종료 상태Bash에서 사용하는 종료 코드만 나열하지만 그 코드가 무엇인지는 밝히지 않습니다.예약된또는 자신의 스크립트/프로그램과 함께 사용하지 말라는 경고입니다.

답변1

아니요종료 코드특별한 의미가 있지만 in의 값도 $?특별한 의미를 가질 수 있습니다.

$?문제는 Bourne Shell과 ksh93이 종료 코드와 오류 조건을 처리하고 이를 쉘 변수로 전달하는 방식 입니다. 귀하가 나열한 것과는 달리 다음 값만 $?특별한 의미를 갖습니다.

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

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

  • Bourne Shell bash 및 ksh88은 128 + 세마포어를 사용합니다.
  • ksh93은 256개 이상의 신호 번호를 사용합니다.

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

특히, 1과 2의 값은 특수한 조건에 사용되는 것이 아니고, 단순히 내장 명령어에서 사용하는 종료 코드일 뿐, 내장 명령어가 아닐 때에도 동일한 용도로 사용됩니다. 포인터가 다음을 가리키는 것처럼 보입니다.Bash 스크립팅 가이드당신이 제공한 매뉴얼은 특정 코드가 당신의 스크립트에서 피해야 하는 특별한 값인지에 대한 언급 없이 bash에서 사용하는 코드만 나열하기 때문에 좋은 것이 아닙니다.

최신 버전의 Bourne Shell은 프로그램이 종료될 때까지 기다리는 waitid()대신 (1989년 SVr4용으로 도입됨) 더 나은 시스템 호출 인터페이스(1980년 UNOS에서 사용된 인터페이스와 유사)를 사용합니다.waitpid()waitid()

최신 Bourne Shell 버전 인코딩 사용탈퇴 이유별도의 변수 에 ${.sh.code}/${.sh.codename}종료 코드${.sh.status}/ ${.sh.termsig}에 위치http://schillix.sourceforge.net/man/man1/bosh.1.html, 종료 코드는 특별한 조건으로 인해 오버로드되지 않으며 `waitid() 사용 덕분에 Bourne Shell은 이제 하위 8비트뿐만 아니라 모든 32비트 종료 코드 반환을 지원합니다.

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

답변2

프로세스 종료 코드의 의미를 표준화하려는 시도가 많이 있었습니다. 당신이 언급한 것 외에도 나는 다음 사항도 알고 있습니다.

  • BSD는sysexits.h64부터 시작하는 값의 의미를 정의합니다.

  • GNU grep문서의 종료 코드 0은 적어도 하나의 일치 항목이 발견되었음을 의미하고, 1은 일치 항목이 발견되지 않았음을 의미하며, 2는 I/O 오류가 발생했음을 의미합니다. 이 규칙은 "아무것도 잘못되지 않았습니다. 하지만 "아무것도 찾지 못했습니다"와 "I/O 오류가 발생했습니다"의 차이점은 의미가 있습니다.

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

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

특정 프로그램이 이러한 규칙을 준수할 것이라고 기대할 수는 없습니다. 오직믿을 수 있는규칙에 따르면 종료 코드 0은 성공을 나타내고 다른 코드는 실패를 나타냅니다. (C89 EXIT_SUCCESS아니요값은 0이 보장되지만 값이 다르더라도 동일하게 동작해야 합니다 exit(0). )exit(EXIT_SUCCESS)

답변3

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.sh생성할 수 있습니다 .exit.sh.shexit2strexit2str.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특히 다른 코드는 많지 않지만 매우 일반적입니다. 나는 게으른 사람들을 위한 (1)이 항상 있지만, 때때로 루틴을 따르려고 노력합니다 $S_EX_ANY(나도 그들 중 하나입니다).

답변4

종료 코드를 기록하여 1년 후 다시 돌아가서 스크립트를 수정해야 할 때 기억할 수만 있다면 문제가 없을 것입니다. "종료 코드 보존"이라는 개념은 관례적으로 성공 코드로 사용되는 코드 0와 실패 코드로 사용되는 다른 코드를 제외하고는 더 이상 실제로 적용되지 않습니다.

관련 정보