본문 바로가기
C.W.K.
Stream
Lesson 09 of 12 · published

에러 처리: set -euo pipefail

~13 min · set, errexit, pipefail, nounset

Level 0창 구경꾼
0 XP0/95 lessons0/14 achievements
0/100 XP to next level100 XP to go0% complete

실패를 빨리 드러내는 헤더

#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'

이 설정은 흔히 ‘strict 모드’라고 불리지만 만능 안전벨트는 아니야. 숨은 실패를 드러내는 데 도움을 주는 대신, 각 옵션의 예외 규칙을 모르면 정상적인 분기까지 뜻밖에 종료시킬 수 있어.

각 옵션이 무엇을 바꾸는지 알아 둬

  • -e 또는 errexit는 명령이 0이 아닌 값을 반환하면 스크립트를 종료해. 다만 조건식과 파이프라인처럼 예외가 적용되는 문맥이 있어.
  • -u 또는 nounset은 정의되지 않은 변수를 참조하면 스크립트를 종료해. $PROOJECT처럼 변수 이름을 잘못 쓴 실수를 드러내 줘.
  • -o pipefail은 마지막 명령만 성공했다고 해서 앞 단계의 실패를 숨기지 않고, 그 실패를 파이프라인 전체의 종료 상태에 반영해.
  • IFS 변경은 전역 단어 분리 규칙을 바꿔. 오래된 strict 모드 관용구지만 모든 스크립트에 필요한 것은 아니야. 필요한 입력 지점에서 값을 인용하고 IFS= read -r를 사용하는 편이 영향 범위가 더 작아.

-e가 바로 종료하지 않는 문맥이 있어

명령이 if의 조건이거나 && 목록과 파이프라인의 일부일 때는 set -e가 곧바로 스크립트를 끝내지 않을 수 있어. 호출한 쪽에서 종료 상태를 직접 판단해야 하는 경우에는 이 동작을 다음처럼 명시적으로 사용해.

# 호출한 쪽에서 종료 상태를 검사
if grep -q ERROR build.log; then ...

# 실패를 허용하더라도 이유를 남기고 대상을 검증
if ! optional_cleanup; then
  printf 'warning: cleanup skipped\n' >&2
fi

-u를 쓸 때는 기본값과 필수값을 구분해

-u에서는 설정되지 않은 변수를 읽으면 종료돼. 선택 입력은 ${var:-}${var:-fallback}처럼 기본값을 명시하고, 필수 입력은 ${var:?message}로 계약을 드러내.

읽고 바로 조치할 수 있는 오류를 남겨

err() { echo "$0:${LINENO}: $*" >&2; exit 1; }
[[ -d "$dir" ]] || err "missing $dir"

작은 err 도우미 함수는 어느 스크립트의 몇 번째 줄에서 무엇이 실패했는지 알려 줘서 바로 조치할 수 있게 해. 다음 레슨의 trap과 함께 사용하면 종료할 때 필요한 정리도 묶을 수 있어.

-e보다 명시적 분기가 중요한 단계가 있어

errexitif, while, 논리 연산자, 함수 호출 문맥에서 직관과 다르게 동작할 수 있어. 데이터 삭제, 배포, 백업처럼 실패 의미가 중요한 단계는 if ! command; then ... fi로 직접 처리하고 무엇이 실패했는지 남겨. 옵션은 판단을 줄여 주는 보조 장치지 판단 자체가 아니야.

파이프라인은 어느 단계가 깨졌는지 봐야 해

pipefail은 앞 단계 실패를 숨기지 않게 하지만, 여러 단계 가운데 정확히 어디가 실패했는지 설명까지 해 주지는 않아. 복구가 필요한 파이프라인은 단계를 나누거나 PIPESTATUS를 확인해. 한 줄을 짧게 만드는 것보다 실패를 재현할 수 있게 만드는 게 우선이야.

Code

방어적 bash 헤더·bash
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'

err() { echo "${0}:${LINENO}: $*" >&2; exit 1; }

: "${INPUT:?INPUT env var required}"
[[ -f "$INPUT" ]] || err "$INPUT does not exist"

wc -l < "$INPUT"

External links

Exercise

기존 시험 스크립트 하나에 set -euo pipefail을 추가하고 실행해. 새로 드러난 실패가 있다면 단순히 예외 처리로 숨기지 말고 변수 오타, 의도한 비영 종료와 파이프라인 상태 가운데 무엇인지 구분해 한 곳을 고쳐.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.