![Bash에서 SIGPIPE를 억제하는 방법은 무엇입니까?](https://linux55.com/image/171984/Bash%EC%97%90%EC%84%9C%20SIGPIPE%EB%A5%BC%20%EC%96%B5%EC%A0%9C%ED%95%98%EB%8A%94%20%EB%B0%A9%EB%B2%95%EC%9D%80%20%EB%AC%B4%EC%97%87%EC%9E%85%EB%8B%88%EA%B9%8C%3F.png)
다음 코드를 실행하려고 합니다.
set -euxo pipefail
yes phrase | make installer
Makefile
표준 입력을 사용하여 설치 phrase
프로그램 파일을 만듭니다. 그러나 이 명령은 CI 빌드를 중단시키는 오류 코드 141로 끝납니다. 이 예는 다음과 같이 단순화될 수 있습니다.
yes | tee >(echo yo)
여기에서 볼 수 있습니다:출력을 티로 배관할 때 파이프 실패(141) - 이유는 무엇입니까?- 이 오류는 파이프 소비자가 출력 소비를 중단했음을 의미합니다. 제 경우에는 전혀 문제가 없습니다.
파이프 오류를 억제하고 그로부터 반환 코드만 가져오는 방법이 있습니까 make installer
?
답변1
141 종료 코드는 프로세스가 실패했음을 나타내며 SIGPIPE
이는 yes
파이프가 닫힐 때 발생합니다. CI에 대해 이 오류를 마스킹하려면 다음과 같은 것을 사용하여 오류를 마스킹해야 합니다.
(yes phrase ||:) | make installer
그러면 실행되고 yes phrase
, 실패하면 :
코드 0으로 실행하고 종료합니다. yes
쓸 수 없는 것 외에는 실패할 이유가 별로 없기 때문에 이 방법은 충분히 안전합니다 .
이러한 유형의 파이프라인 문제를 디버깅하는 가장 좋은 방법은 다음을 살펴보는 것입니다 PIPESTATUS
.
yes phrase | make installer || echo "${PIPESTATUS[@]}"
그러면 실패 시 파이프라인의 모든 부분에 대한 종료 코드가 표시됩니다. 종료 코드 141로 인해 실패하는 경우는 적절하게 처리될 수 있습니다. 특정 오류 코드에 대한 일반적인 처리 패턴은 다음과 같습니다.
(command; ec=$?; if [ "$ec" -eq 141 ]; then exit 0; else exit "$ec"; fi)
(감사해요하우크라그); command
성공하면 코드 0으로 실행되고 종료되고 command
, 성공하면 코드 141로 종료됩니다. 다른 종료 코드는 그대로 반영됩니다.
답변2
파이프 오류를 억제하고 그로부터 반환 코드만 가져오는 방법이 있습니까
make installer
?
하위 쉘에서 전체 명령 파이프라인을 실행하고 싶지 않은 경우(예: 변수를 설정할 수 있기를 원하는 경우) 게시된 다른 훌륭한 답변에 대한 대체 솔루션을 사용할 수 있습니다.
yes phrase | make installer || { ec=$?; [ $ec -eq 141 ] && true || (exit $ec); }
# generic syntax:
cmd1 | cmd2 | cmd3 || { ec=$?; [ $ec -eq 141 ] && true || (exit $ec); }
이는 exit
하위 셸의 명령을 사용하여 명령 파이프라인에 원래 종료 코드를 그대로 둡니다(141이 아닌 경우). 따라서 set -e
( set -o errexit
)가 와 함께 작동하면 원하는 효과를 얻을 수 있습니다 set -o pipefail
.
return
대신 서브쉘 트릭에 사용할 수 있는 함수를 사용하면 더 깔끔한 코드를 얻을 수 있습니다 .exit
handle_pipefails() {
# ignore exit code 141 from simple command pipes
# - use with: cmd1 | cmd2 || handle_pipefails $?
(( $1 == 141 )) && return 0
return $1
}
# then use it or test it as:
yes | head -n 1 || handle_pipefails $?
echo "ec=$?"
# then change the tested code from 141 to e.g. 999 in
# the function, and see that ec was in fact captured as
# 141
더 복잡한 파이프라인과 관련된 다른 명령의 종료 코드를 테스트하려는 경우 또 다른 접근 방식은 전체 PIPESTATUS를 테스트하는 것입니다.
handle_pipefails2() {
# ignore exit code 141 from more complex command pipes
# - use with: cmd1 | cmd2 | cmd3 || handle_pipefails2 "${PIPESTATUS[@]}"
for x in "$@"; do
(( $x == 141 )) || { (( $x > 0 )) && return $x; }
done
return 0
}
답변3
( yes phrase ; exit 0 ) | make installer
답변4
약간의 조사 끝에 다음 답변을 찾았습니다.https://stackoverflow.com/questions/22464786/ignoring-bash-pipefail-for-error-code-141#comment60412687_33026977 기본적으로 다음을 사용하십시오.
set -euxo pipefail
yes phrase | make installer || (ec=$? ; if [ "$ec" -eq 141 ]; then exit 0; else exit "$ec"; fi)
SIGPIPE
반환 코드에서 필터링되었습니다.