← 아티클 목록

bash 스크립트 흔한 함정과 set -e 안전 설정법

2027-10-18#linux#bash#트러블슈팅

bash 스크립트의 가장 무서운 점은 에러가 나도 멈추지 않고 다음 줄을 계속 실행한다는 것입니다. cd /backup 이 실패했는데 다음 줄 rm -rf * 가 그대로 돌면 엉뚱한 디렉터리를 지웁니다. 운영 사고 대부분이 여기서 시작됩니다.

기본값이 위험한 이유

아무 설정 없는 bash는 명령이 실패해도 종료 코드를 무시하고 진행합니다.

로컬 터미널
#!/bin/bash
cd /data/backup      # 디렉터리가 없으면 실패
rm -rf ./*           # 그래도 실행됨 → 현재 위치에서 삭제

cd 가 실패하면 스크립트는 호출 시점의 작업 디렉터리에 머문 채 rm 을 실행합니다. 실패를 멈추지 않은 대가입니다.

안전 3종 세트 — set -euo pipefail

스크립트 맨 위에 다음 한 줄을 넣는 것이 사실상 표준입니다.

로컬 터미널
#!/bin/bash
set -euo pipefail
옵션효과막아주는 사고
set -e명령이 실패(0이 아닌 종료)하면 즉시 중단실패 후 다음 줄 강행
set -u정의되지 않은 변수 참조 시 에러오타 변수가 빈 값으로 치환
set -o pipefail파이프 중 하나라도 실패하면 전체 실패 처리`cmd

set -u 가 없으면 rm -rf "$PREFIX/cache" 에서 PREFIX 오타가 빈 값이 되어 rm -rf /cache 로 돌변합니다. pipefail 이 없으면 curl ... | grep ok 에서 curl 이 죽어도 파이프라인은 grep 의 종료 코드만 봐서 성공으로 오인합니다.

set -e 의 함정과 회피

set -e 는 만능이 아닙니다. 일부러 실패를 허용해야 하는 곳에서 스크립트가 죽어버립니다.

로컬 터미널
# grep이 매칭 못 하면 종료코드 1 → set -e가 스크립트를 죽임
if grep -q "ERROR" app.log; then
  echo "에러 발견"
fi
# 조건문 안에서는 set -e가 적용되지 않으므로 안전

# 실패를 허용하고 싶을 때
some_optional_cmd || true

조건문(if, while, &&, ||) 안의 명령은 set -e 대상에서 제외되므로, 실패가 정상인 검사는 반드시 조건문이나 || true 로 감쌉니다.

작성 전 체크리스트

로컬 터미널
set -euo pipefail                 # 맨 위 고정
trap 'echo "실패: line $LINENO"' ERR  # 어디서 죽었는지 출력
"${VAR:?VAR가 설정되지 않음}"      # 필수 변수 강제
bash -n script.sh                 # 실행 전 문법 검사
shellcheck script.sh              # 정적 분석으로 함정 사전 탐지

특히 trap ... ERR 로 실패 지점을 로그에 남기면, set -e 로 조용히 멈춘 스크립트도 어느 줄에서 죽었는지 바로 알 수 있습니다.


set -euo pipefail 부터 trap, shellcheck 까지 방어적 bash 작성을 직접 실습하고 운영 스크립트 감각을 익히는 과정은 리눅스 트랙에서 회원가입 없이 무료로 시작할 수 있습니다.