![가끔 발생하는 141 셸 스크립트 오류 디버깅](https://linux55.com/image/171164/%EA%B0%80%EB%81%94%20%EB%B0%9C%EC%83%9D%ED%95%98%EB%8A%94%20141%20%EC%85%B8%20%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%20%EC%98%A4%EB%A5%98%20%EB%94%94%EB%B2%84%EA%B9%85.png)
CI(Gitlab, Alpine Linux를 실행하는 Docker 컨테이너)에서 스크립트를 실행할 때 신호 141이 "SIGPIPE"를 의미하는 것처럼 보이는 산발적인 오류가 발생했습니다. 하지만 어떤 단계가 실패하는지, 어떻게 디버깅하는지 이해할 수 없습니다.
#!/usr/bin/env bash
set -euxo pipefail
set -a
# ...
git fetch --tags
RELEASE=$(git tag | grep -E "${BUILD_ENV}-release-(\d+)" | cut -d"-" -f3 | sort -nr | head -1)
RELEASE=$(( RELEASE + 1 ))
파이프라인의 마지막 줄에서 두 번째 줄 내에서 산발적인 오류가 발생하는 것 같습니다. 내가 받은 로그는 다음과 같습니다.
++ git tag
++ cut -d- -f3
++ sort -nr
++ grep -E 'prod-release-(\d+)'
++ head -1
+ RELEASE=323
ERROR: Job failed: exit code 141
실제로 어떤 라인이 실패하는지 알아내기 위해 이것을 어떻게 디버깅합니까? RELEASE 변수를 성공적으로 채운 것처럼 보이지만 여전히 문제가 발생합니까?
답변1
head -1
작업이 완료된 후에는 sort -nr
파이프에 모든 데이터를 쓸 수 있는지 여부에 관계없이 종료됩니다. sort
쓸 내용이 더 있고 head
더 이상 없으면 그걸로 충분 sort
합니다 SIGPIPE
.
아무것도 폭발하지 않습니다. 이것이 파이프가 작동하는 방식입니다. 파이프라인에서 사용할 때 head
이전 명령이 SIGPIPE
.
yes
대신 간단한 테스트 sort
:
$ set -o pipefail
$ yes | head -n 1
y
$ printf '%s\n' "$?" "${PIPESTATUS[@]}"
141 <- overall exit status
141 <- from `yes'
0 <- from `head'
종료 상태는 이며 141
, 출처는 입니다 yes
.
디버깅 방법을 보여줍니다 ${PIPESTATUS[@]}
.
이 동작은 예상됩니다. 파이프라인의 이 부분의 종료 상태를 조작하려면 대신 yes
(또는 귀하의 경우에는 대신 ) subshell을 사용하십시오. sort
예:
$ set -o pipefail
$ (yes; true) | head -n 1
y
$ printf '%s\n' "$?" "${PIPESTATUS[@]}"
0
0
0
더 복잡한 논리만 억제합니다 141
.
(yes; e="$?"; [ "$e" -eq 141 ] && exit 0; exit "$e") | head -n 1