파이프를 사용할 때 종료 상태를 전달하는 방법을 이해하려고 합니다. which
존재하지 않는 프로그램을 찾는 데 사용한다고 가정해 보겠습니다 .
which lss
echo $?
1
내 종료 상태는 which
찾기 실패 로 인해 1입니다. lss
이것은 좋다. 그러나 다음을 시도하면 :
which lss | echo $?
0
이는 마지막으로 실행된 명령이 정상적으로 종료되었음을 나타냅니다. 내가 이해할 수 있는 유일한 방법은 PIPE가 종료 상태를 생성할 수도 있다는 것입니다. 이것이 올바른 이해 방법입니까?
답변1
파이프의 종료 상태는 오른쪽 명령의 종료 상태입니다. 왼쪽 명령의 종료 상태는 무시됩니다.
( which lss | echo $?
이것은 표시되지 않습니다. which lss | true; echo $?
이를 표시하려면 실행해야 합니다. 에서는 which lss | echo $?
이 echo $?
파이프라인 이전의 마지막 명령 상태가 보고됩니다.)
쉘이 이렇게 하는 이유는 왼쪽의 오류를 무시해야 하는 매우 일반적인 상황이 있기 때문입니다. 왼쪽이 여전히 쓰고 있는 동안 오른쪽이 나가면(또는 더 일반적으로는 표준 입력을 닫는 경우) 왼쪽은 SIGPIPE 신호를 받습니다. 이 경우 일반적으로 문제가 없습니다. 오른쪽은 데이터에 관심이 없고 오른쪽은 데이터에 관심이 없습니다. 왼쪽에서 수행하는 작업이 이 데이터를 생성하는 것뿐이라면 중지할 수 있습니다.
그러나 SIGPIPE 이외의 다른 이유로 왼쪽이 죽거나 표준 출력에서 데이터를 생성하는 것 이상의 작업을 수행하는 경우 왼쪽의 오류는 실제 오류이므로 보고되어야 합니다.
일반 sh에서 유일한 해결책은 명명된 파이프를 사용하는 것입니다.
set -e
mkfifo p
command1 >p & pid1=$!
command2 <p
wait $pid1
ksh, bash 및 zsh에서는 파이프의 구성 요소가 0이 아닌 상태로 종료되는 경우 0이 아닌 상태로 파이프를 종료하도록 쉘에 지시할 수 있습니다. 옵션을 설정해야 합니다 pipefail
.
- 크쉬:
set -o pipefail
- 큰 타격:
shopt -s pipefail
- zsh: (
setopt pipefail
또는setopt pipe_fail
)
PIPESTATUS
mksh, bash 및 zsh에서는 마지막 파이프라인(일반화 ) pipestatus
의 모든 명령 상태를 포함하는 배열인 변수(bash, mksh) 또는 (zsh)를 사용하여 파이프라인의 각 구성 요소 상태를 가져올 수 있습니다 .$?
답변2
파이프의 종료 상태는 파이프라인의 마지막 명령의 종료 상태입니다( pipefail
셸 옵션이 이를 지원하는 셸에 설정되지 않은 경우 종료 상태는 파이프라인의 마지막 명령의 종료 상태가 됩니다). .
파이프의 종료 상태를 인쇄할 수 없습니다.안으로부터파이프는 파이프가 실제로 실행을 완료할 때까지 값이 무엇인지 알 수 있는 방법이 없기 때문입니다.
관로
which lss | echo $?
표준 입력을 읽을 수 없기 때문에 의미가 없습니다 echo
(파이프는 한 명령의 출력과 다음 명령의 입력 사이에 데이터를 전달하는 데 사용됩니다). 또한 echo
파이프의 종료 상태를 인쇄 하지 않지만 즉시 실행 명령의 종료 상태를 인쇄합니다.앞으로관로.
$ false
$ which hello | echo $?
1
which: hello: Command not found.
$ true
$ which hello | echo $?
0
which: hello: Command not found.
더 나은 예는 다음과 같습니다.
$ echo hello | read a
$ echo $?
0
$ echo nonexistent | { read filename && rm $filename; }
rm: nonexistent: No such file or directory
$ echo $?
1
이는 파이프를 다음과 함께 사용할 수도 있음을 의미합니다 if
.
if gzip -dc file.gz | grep -q 'something'; then
echo 'something was found'
fi
답변3
예, PIPE는 종료 상태를 생성합니다. PIPE 이전에 명령의 종료 코드를 원하는 경우 사용할 수 있습니다.$PIPESTATUS
~에 따르면이 스택 오버플로 Q&A, 파이프를 사용할 때 명령의 종료 상태를 인쇄하려면 다음을 수행할 수 있습니다.
your_command | echo $PIPESTATUS
또는 명령을 사용하여 파이프라인 실패를 설정 set -o pipefail
(설정 해제, 실행 set +o pipefail
)한 다음 $?
대신 를 사용하십시오 $PIPESTATUS
.
your_command | echo $?
이 명령은 적어도 한 번 실행하는 경우에만 작동합니다. 즉, PIPESTATUS
다음과 같이 파이프를 사용하여 명령 다음에 실행하는 경우에만 작동합니다.
command_which_exit_10 | command_which_exit_1
echo "${PIPESTATUS[0]} ${PIPESTATUS[1]}"
${PIPESTATUS[0]}
10포인트 와 1포인트를 받게 됩니다 ${PIPESTATUS[1]}
. 바라보다이번 U&L Q&A더 많은 정보를 알고 싶습니다.
답변4
셸은 파이프라인을 실행하기 전에 명령줄을 평가합니다. $?
파이프라인 이전에 실행된 마지막 명령의 값도 마찬가지입니다. echo
이전에 시작되었는지 이후에 시작되었는지는 중요 하지 which
않습니다 .
이제 질문이 종료 상태 전파에 관한 것이라면 다음과 같은 기본 동작을 살펴볼 수 있습니다.
% false | true
% echo $?
0
% true | false
% echo $?
1
보시다시피 파이프라인의 종료 상태는 마지막 명령의 종료 상태입니다.