실패한 고양이는 1을 반환하고 다른 실패한 고양이는 2를 반환하는 이유는 무엇입니까?

실패한 고양이는 1을 반환하고 다른 실패한 고양이는 2를 반환하는 이유는 무엇입니까?

고려 사항: (Linux/BASH 사용, UNIX가 올바른지 확실하지 않음)

존재하지 않는 파일에 대해 논쟁할 때 2개의 오류가 예상되었습니다...

grep "i am here" real-file

# Returns: 0 (via: echo $?)

grep "i am not here" real-file

# Returns: 1

grep "i am not here" not-a-file

# Returns: 2 (No such file or directory)

ls real-files

# Returns: 0

ls not-files

# Returns: 2 (No such file or directory)

…모두 말이 되지만…

cat real-files

# Returns: 0

cat not-files

# Returns: 1 (No such file or directory)

..."해당 파일이나 디렉터리가 없습니다"는 종료 상태 2의 STDERR이 아니어야 합니까?

상태 2에는 파일이 있고 grep파일 ls이 없지만 cat동일한 오류 메시지와 함께 1을 반환합니다.

나는 grep세 가지 가능한 결과(위 각각)가 있다는 것을 알고 있지만 ls두 가지만 있을 것이라고 생각합니다 cat. 그러므로 두 가지 가능한 결과는 원인이 될 수 cat없습니다 ls.

BASH 코드에 문제가 있습니까? Linus와 Richard에게 전화해야 하나요? 이것이 맞다면 그 이유를 이해하도록 도와주세요.


답변을 수락한 후 원래 질문을 확장하는 답변을 원합니다. 이는 UNIX가 아니라 Linux/BASH이기 때문입니다. 올바른: UNIX(예: Mac에서)가 동일한 작업을 수행합니까 아니면 유사한 작업을 수행합니까?

답변1

아래에서 위로 일부 부분을 다루고 중요하지 않은 부분을 먼저 제거해 보겠습니다.

BASH 코드에 문제가 있습니까?

아니요, 일부 셸 구성에서 지적한 것처럼 cat완전히 독립형 바이너리 애플리케이션입니다.bash스티븐 차제라스, cat내장될 수 있지만 애플리케이션의 반환 상태는 애플리케이션이 셸 관련인지 여부와 완전히 독립적입니다.

Linus와 Richard에게 전화해야 하나요? 이것이 맞다면 그 이유를 이해하도록 도와주세요.

아니요, 그건 문제가 되지 않습니다. Linus와 Richard는 여기서 전혀 할 일이 없습니다. 글쎄요, 정정합니다. 언젠가 그들이 errno exit()와 errno가 절대적으로 관련되어야 한다고 말하고 어떤 이상한 이유로 우리는 그들의 모든 기술적 결정을 따라야 한다고 말하지 않는 한 말입니다.


두 애플리케이션이 서로 다른 종료 상태를 반환하는 것은 전혀 문제가 되지 않습니다.POSIX 사양에는 "0이 아닌 종료 상태가 이것저것을 의미한다"는 명시적인 제한이나 할당이 없습니다.

종료 시스템 호출에 대한 POSIX 문서상태:

상태 값은 0, EXIT_SUCCESS, EXIT_FAILURE 또는 기타 값일 수 있지만 대기 중인 상위 프로세스에는 최하위 8비트(즉, 상태 및 0377)만 사용할 수 있습니다.

이는 상태 0만이 지정된 의미를 가지며, 이는 다음에 지정된 대로 EXIT_SUCCESS에 할당됨을 의미합니다.표준 라이브러리 파일안경. 그러나 이것은 POSIX 사양입니다. Linux 사양은 어떻게 비교됩니까? 음, 거의 같은 것입니다: Linux출구(3)매뉴얼에는 가능한 값도 지정되어 있지 않습니다.

또한 "~해야 한다"가 아니라 "~일 수도 있다"라고 쓰여 있다는 점에 유의하세요.애플리케이션이 특정 값으로 종료될 필요는 없습니다., 오류가 발생하더라도. 애플리케이션에 오류가 발생하거나 실패할 수 있지만 여전히 0으로 종료됩니다.

그러나 POSIX 사양은모든 휴대용 애플리케이션용EXIT STATUS 부분이 실제로 지정되었습니다.각 응용 프로그램에 따라 다릅니다.다시 말하지만, 성공의 경우 0 이외의 패턴은 없고 그 밖의 다른 경우에는 0이 아닌 패턴이 없습니다. 예를 들어,POSIX 고양이 사양필요하다:

The following exit values shall be returned:

0    All input files were output successfully.

>0   An error occurred.

~을 위한grep우리는:

The following exit values shall be returned:

 0    One or more lines were selected.
 1    No lines were selected.
>1    An error occurred.

리눅스 환경에서는고양이(1)이러한 상태값은 명시적으로 명시되어 있지는 않지만,GNU 문서는.정규식(1)매뉴얼에는 종료 코드 2를 사용하는 것이 언급되어 있지만 POSIX 구현에는 0보다 큰 오류 조건만 필요하다는 점을 인정하고 "... 이식성을 위해 2와의 엄격한 동일성 대신 이 일반 조건을 테스트하는 논리를 사용하십시오."라고 촉구합니다.


exit()어떤 경우에는 상태 값이 다음과 같다고 가정한다는 점은 언급할 가치가 있습니다.오류 번호값. 지금까지 POSIX에서 이를 요구한다는 문서나 참고 자료를 찾을 수 없습니다. 실제로는 그 반대가 사실입니다. POSIX에 주목하세요출구규범과 리눅스출구(3) 매뉴얼 페이지원하지 않는다종료 상태가 어떤 방식으로든 errno와 일치해야 함을 명시적으로 나타냅니다. 따라서 반환 값 2와 GNU의 grepENOENT 오류 값 2 사이의 일치는 순전히 우연입니다.

사실 생각해 보면오류 번호 특정 정수 값을 할당할 필요조차 없으며 구현에 따라 다릅니다. 따라서 ENOENT를 정수 2로 처리하는 Unix와 유사한 구현이 있을 가능성이 높습니다. 그러나 종료 상태와 errno는 다르기 때문에 이것은 전혀 관련이 없습니다.

요약하자면:

실제로 cat반환된 종료 코드는 grep다르며 해당 응용 프로그램의 사양과 일치하고 적절합니다. 종료 코드의 의미는 고정되어 있지 않으며 각 개별 애플리케이션에 따라 다릅니다( cat또는 와 같은 POSIX 애플리케이션이 아닌 grep경우 이식성을 위해 따라야 합니다).

견적으로 이동GNU 운영 체제 문서: "가장 일반적인 규칙은 0은 성공을 의미하고 1은 실패를 의미한다는 것입니다. 비교를 수행하는 프로그램은 다른 규칙을 사용합니다. 즉, 불일치에 대해 상태 1을 사용하고 비교 실패에 대해 상태 2를 사용합니다. 다음과 같은 경우 프로그램은 기존 규칙을 따라야 합니다. 그들에게 의미가 있는 합의가 있습니다.”

답변2

암소 비슷한 일종의 영양coreutils 문서cat:

종료 상태 0은 성공을 나타내고, 0이 아닌 값은 실패를 나타냅니다.

...0이 아닌 종료 상태는 실패만을 의미합니다.

다음에 대한 매뉴얼 페이지 grep:

일반적으로 종료 상태는 행이 선택된 경우 0, 행이 선택되지 않은 경우 1, 오류가 발생한 경우 2입니다. 그러나 -q또는 를 사용하여 행을 선택하면 --quiet오류 --silent가 발생하더라도 종료 상태는 0입니다.

그리고 다음 매뉴얼 페이지 ls:

종료 상태:
0은 정상,
1은 사소한 문제(예: 하위 디렉터리에 액세스할 수 없음),
2는 심각한 문제(예: 명령줄 인수에 액세스할 수 없음)입니다.

결과는 문서와 일치합니다.

답변3

프로그램의 종료 상태는 이러한 규칙 외에도 몇 가지 일반적인 규칙을 따라야 합니다. 이러한 규칙은 프로그램 종료를 유발하는 낮은 수준의 오류와는 아무런 관련이 없습니다. 종료할 때 특정 오류 코드를 표시하고(파일이 존재하지 않기 때문에 종료하기로 결정), 파일에 대한 접근이 거부되어 종료하기로 결정하면 다른 오류 코드를 표시하는 프로그램을 작성할 수 있습니다. 경로의 디렉터리 구성 요소가 디렉터리가 아닌 것으로 밝혀지면 다른 오류 코드가 발생합니다. 그러나 이는 매우 이례적이며 정리하기 어렵습니다.

프로그램의 종료 상태는 정수 값입니다. 존재하다POSIX 시스템, 이 값의 유형은 int일반적으로 값 범위는 -2 31 ~ 2 31 +1입니다. 그러나 이 범위의 대부분은 여러 가지 이유로 실제로 사용할 수 없습니다. 무엇보다도 역사적인 이유로 프로그램이 하위 프로세스의 종료 상태를 관찰할 수 있도록 하는 대부분의 인터페이스는 종료 상태의 하위 8비트(0에서 255 사이의 값)만 반환합니다. 여기에는 시스템 기능이 포함됩니다.wait그리고waitpid게다가쉘의 종료 상태².따라서 거의 모든 의도와 목적에 따라 종료 상태는 8비트 값입니다.

0 값은 성공으로 간주되고, 다른 모든 값은 실패로 간주됩니다. 이는 쉘의 경우입니다.부울 연산자,if그리고 while빌드true/false 개념과 관련된 다른 모든 항목은 종료 상태 0을 true로 처리하고 다른 모든 상태를 false로 처리합니다. 이것도 마찬가지다make0이 아닌 종료 상태로 인해 오류 메시지 및 오류 상태와 함께 빌드가 중지됩니다. 이것이 관례인지 의문을 제기할 수 있습니다(기술적으로 프로그램 작성자는 원하는 상태를 반환할 수 있고 "성공"과 "실패"는 공식적으로 정의되어 있지 않기 때문입니다). 그러나 실제로는 상태로 시작합니다. 0이면 성공한 것으로 간주되고, 다른 상태(1-255)로 종료되는 프로그램은 실패한 것으로 간주됩니다.

인클로저의 특히 범위를 제한하는 또 다른 특징은 다음과 같습니다.쉘의 종료 상태$?추가 정보 인코딩 (관찰을 통해 ):

  • 126은 명령 이름이 기존 파일이므로 실행할 수 없음을 의미합니다.
  • 127은 명령 이름을 찾을 수 없음을 의미합니다.
  • 128+질소전통적으로(그리고 오늘날에도 여전히 대부분의 쉘에서) 명령은 신호와 함께 종료하라는 지시를 받았습니다.질소. 일부 쉘은 항상 128을 초과하는 다양한 범위를 사용합니다.

따라서 실제로 프로그램은 125보다 큰 종료 상태를 효과적으로 사용할 수 없습니다. 이를 통해 1-125 값이 다양한 오류를 나타낼 수 있습니다.

더 큰 값이 "더 나쁜" 실패로 간주된다는 보편적인 관습과는 거리가 멀지만 널리 퍼져 있습니다. 특히 검색 명령의 경우 grep1은 "찾을 수 없음"을 의미하고 2 이상은 검색을 방해하는 일부 오류를 의미합니다(예를 들어, 파일을 찾았지만 검색 문자열을 포함하지 않는 것과 달리 파일을 찾을 수 없음). 마찬가지로 다음과 같은 비교 명령도 있습니다.cmp그리고diff종료 상태 0은 "동일한 파일"을 의미하고, 1은 "다른 파일"을 의미하며, 2 이상은 "오류로 인해 비교를 완료할 수 없음"을 의미합니다.

일부 프로그램은 다양한 오류에 대해 서로 다른 오류 코드를 정의합니다.이메일을 보내및 기타 메일 관련 프로그램(에 정의된 값)sysexits.h),동기화,곱슬,얻다.

오류 코드에 대한 가장 일반적인 규칙은 성공의 경우 0이고 실패의 경우 1입니다. C 및 C++ 프로그래밍 언어 정의EXIT_FAILURE종료 상태 코드로, 특정 값을 선택해야 하는 특별한 이유가 없는 경우 실패를 보고하는 데 사용되며 EXIT_FAILURE대부분의 시스템에서 1입니다.

"해당 파일 또는 디렉터리 없음", "권한이 거부됨", "디렉터리가 아님" 등과 같은 오류에는 뒤에 숫자 코드가 있습니다.errno무엇이 잘못되었는지 나타내기 위해 시스템 기능에 의해 반환되는 값입니다. Errno 값은 일반적으로 프로그램의 종료 상태로 사용되지 않습니다. 특정 프로그램에 대한 의미보다는 무엇이 잘못되었는지에 대한 세부 정보를 인코딩합니다. 예를 들어얻다종료 상태는 "옵션의 구문 분석 오류"(일반적으로 기본 시스템 오류 없음), "로컬 입력/출력 오류"(기본 시스템 오류에 관계 없음), "네트워크 오류"(대체로 로컬 시스템 오류와 동일)를 구분합니다. wget이 손상된 파이프(파이프에 쓰거나 네트워크 소켓에서 연결을 닫는 등)로 인해 실패했는지 아는 것보다 네트워크 오류나 로컬 파일 오류로 인해 wget이 실패했는지 여부를 아는 것이 더 유용할 것입니다. 구성 파일을 읽을 수 없거나 로컬 정책 네트워크 액세스가 거부되었습니까?

반환 상태가 errno 값을 따르는 것은 덜 일반적입니다. Perl 방식 때문에 특히 Perl 스크립트에서 이런 일이 발생합니다.die기능이 작동합니다. 그러나 이것은 나쁜 생각입니다. 위에서 언급한 것처럼 errno 값이 정보에서 가장 유용한 부분이 아닐 뿐만 아니라 주로 errno 값이 1~125 범위에 있을 이유가 없기 때문입니다. 다행스럽게도 나는 1-255 범위를 벗어나는 errno 값을 갖는 시스템을 알지 못하므로 적어도 exit(errno)(또는 Perl의 경우 die) 256의 배수로 종료되지 않습니다. 이는 위에서 본 것처럼 성공. 하지만리눅스에서, 예를 들어 126까지 올라가며 ("RF-kill로 인해 작업을 수행할 수 없습니다") exit(errno)로 종료되는 프로그램은 SIGILL(불법 명령)으로 종료되는 프로그램과 구별할 수 없습니다.errno == ERFKILL

^ waitidint전체 가치에 대한 액세스 권한을 부여합니다 infop->si_status.
² 또는 다른 방식으로 $?. 예를 들어, exit256로 종료되는 프로그램인 경우 exit(256)쉘 명령은 if exit256; then echo "exited with 0"; fi"exited with 0"을 인쇄합니다.

답변4

시스템에 따라 cat이는 내장 셸일 수도 있고 별도의 바이너리일 수도 있습니다. 그것이 무엇인지 보려면 실행할 수 있습니다

$ command -V cat

또한 catPOSIX를 인용하여 GNU의 동작은 실제로 정확합니다.고양이(1):

종료 상태

다음 종료 값이 반환되어야 합니다.

0
모든 입력 파일을 성공적으로 내보냈습니다.

>0
오류가 발생했습니다.

errno와 종료 상태 사이의 관계는 단지 우연일 뿐입니다. errno는 종료 코드의 하위 8비트 내에 있을 필요가 없기 때문입니다(POSIX에서는 이러한 코드를 전달해야 합니다).

그러나 POSIX '01 호환 SunOS 5.10은 2를 반환합니다(XPG3과 POSIX '01 사이에 표준이 없기 때문에 도구의 동작이 변경되는 것으로 보입니다).

$ PATH=`getconf -v POSIX.1-2001 PATH`
$ export PATH
$ command -v cat
/usr/bin/cat
$ cat nosuchfile
cat: cannot open nosuchfile
$ echo $?
2

ENOENT이는 Solaris에서도 발생합니다.

$ grep ENOENT /usr/include/sys/errno.h
#define ENOENT  2       /* No such file or directory            */

그러나 맨페이지에는 >2만 문서화되어 있습니다.

관련 정보