배포 스크립트 맨 위에 set -euo pipefail 넣어서 어디서 실패하면 바로 죽게 해놨는데, 중간에 분명히 실패하는 명령이 있는데도 스크립트가 그냥 끝까지 진행돼서 잘못된 결과가 배포됐습니다.
문제 구간을 줄여보니 이런 식입니다. 함수 안에서 검사하고, 그 함수를 || 로 감싸서 쓰고 있어요.
set -euo pipefail
check() {
grep -q "OK" build.log # 실패하면 여기서 멈추길 기대
do_deploy
}
check || echo "check failed, continuing anyway"grep이 실패하면 set -e 때문에 함수가 거기서 멈추고 스크립트 전체가 죽을 줄 알았는데, do_deploy 가 그냥 실행돼 버립니다. set -e 가 함수 안에서는 안 먹는 건가요?
댓글 2
규칙은 이래요. 어떤 명령이 && 나 || 나 if while until 나 앞의 ! 같은 조건 리스트의 일부이면, set -e는 그 명령(함수라면 함수 내부까지)에서 발동하지 않습니다. check || echo ... 라고 쓰는 순간 check는 '실패해도 되는 명령'으로 취급돼서, 그 안의 grep이 실패해도 함수가 안 죽고 다음 줄 do_deploy가 그대로 실행됩니다. 이건 POSIX에 명시된 동작이라 버그가 아니라 사양이에요.
해결은 함수를 조건문에 넣지 마세요. 실패를 잡고 싶으면 호출부를 이렇게 바꾸세요.
if ! check; then echo 'failed'; exit 1; fi
이러면 check가 실패했을 때 의도대로 exit 1 로 죽습니다. 반대로 정말 무시하고 싶은 특정 한 줄만 있으면 그 줄만 some_cmd || true 로 감싸시고요.
참고로 set -e는 이 말고도 함정이 많습니다. 파이프는 기본적으로 마지막 명령만 보고(그래서 pipefail을 같이 켠 건 잘하신 거예요), 산술 ((x++)) 결과가 0이면 실패로 쳐서 스크립트가 죽기도 합니다. 크리티컬한 배포 스크립트라면 set -e에만 기대지 말고 중요한 분기는 rc=$? 로 직접 종료코드를 검사하는 걸 권합니다.