0Pricing
DevOps Bootcamp · 강의

정리 및 신호 처리를 위한 트랩 핸들러

EXIT, ERR 및 INT 트랩을 등록하여 임시 파일을 삭제하고 부분적으로 수행된 작업을 안정적으로 되돌립니다.

정리 및 신호 처리를 위한 트랩 핸들러은(는) CoddyKit의 무료 DevOps Bootcamp 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 DevOps Bootcamp 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. DevOps Bootcamp 강의에는 총 4개의 강의가 포함되어 있습니다.

트랩 처리기가 중요한 이유

Bash 스크립트가 정상적으로 종료되거나, 오류로 종료되거나, 사용자가 Ctrl+C를 눌러 종료되면 임시 파일, 일부만 작성된 데이터 또는 손상된 상태가 남을 수 있습니다. 정리하지 않으면 이러한 잔여물이 쌓여 원인을 찾기 어려운 문제를 일으킵니다.

트랩 처리기는 특정 신호 또는 의사 신호를 받았을 때 Bash가 자동으로 실행할 함수나 명령을 등록하여 이 문제를 해결합니다.

  • EXIT — 어떤 이유로든 스크립트가 종료될 때마다 실행됩니다.
  • ERR — 어떤 명령이든 0이 아닌 종료 상태를 반환한 후 실행됩니다.
  • INT — 사용자가 SIGINT (Ctrl+C)를 보낼 때 실행됩니다.
  • TERM — SIGTERM을 받을 때 실행됩니다(예: kill로 보낸 경우).

잘 작성된 스크립트는 위험한 작업을 시작하기 전에 맨 처음에 이러한 트랩을 등록합니다.

trap 내장 명령의 문법

trap 내장 명령은 하나 이상의 신호 또는 의사 신호에 대한 처리기를 등록합니다. 일반적인 문법은 다음과 같습니다.

trap 'command_or_function' SIGNAL [SIGNAL...]

주요 규칙:

  • 첫 번째 인수는 신호가 발생할 때 실행할 셸 코드의 인용 문자열(또는 함수 이름)입니다.
  • 처리기 뒤에 여러 신호를 나열할 수 있습니다.
  • trap '' SIGNAL은 해당 신호를 무시합니다(빈 처리기).
  • trap - SIGNAL은 해당 신호를 기본 동작으로 재설정합니다.

같은 셸에서 호출된 함수는 트랩을 상속하지만, ( ) 또는 &로 생성된 서브셸은 상속하지 않습니다.

#!/usr/bin/env bash
# Syntax examples — not a full script

# Register a cleanup function on EXIT
trap cleanup EXIT

# Inline handler for INT and TERM
trap 'echo "Interrupted!"; exit 1' INT TERM

# Ignore SIGHUP
trap '' HUP

# Reset SIGPIPE to default
trap - PIPE

EXIT 트랩 — 안전망

EXIT 의사 신호는 등록해야 할 가장 중요한 트랩입니다. 셸이 정상적으로 완료되거나, exit N으로 종료되거나, 처리되지 않은 오류 또는 신호로 종료되는 등 어떤 이유로든 종료될 때 실행됩니다. 따라서 임시 파일을 제거하는 데 적합합니다.

권장 방법:

  • mktemp로 임시 파일을 만들어 이름이 고유하고 예측할 수 없도록 합니다.
  • 경로를 즉시 변수에 저장합니다.
  • 생성 직후 EXIT 트랩을 등록하여 항상 정리가 실행되도록 합니다.

스크립트의 종료 코드는 유지됩니다. exit을 그 안에서 명시적으로 호출하지 않는 한 트랩 처리기의 종료 코드는 무시됩니다.

#!/usr/bin/env bash
set -euo pipefail

TMPFILE=$(mktemp /tmp/myapp.XXXXXX)

cleanup() {
    echo "Removing temp file: $TMPFILE" >&2
    rm -f "$TMPFILE"
}
trap cleanup EXIT

# Do real work
echo "Processing..." > "$TMPFILE"
sort "$TMPFILE" -o "$TMPFILE"
cp "$TMPFILE" /tmp/myapp_result.txt

echo "Done. Result saved."

여러 임시 파일과 디렉터리 처리

실제 스크립트는 임시 파일, 디렉터리, FIFO, 잠금 파일 등 여러 임시 리소스를 자주 만듭니다. 각각을 따로 추적하는 대신 배열에 모은 다음 하나의 정리 함수에서 모두 제거할 수 있습니다.

이 방식은 쉽게 확장할 수 있습니다. 새 임시 리소스를 만들 때마다 배열에 추가하면 됩니다. 스크립트가 어디에서 종료되든 EXIT 트랩이 항상 전체 목록을 처리합니다.

#!/usr/bin/env bash
set -euo pipefail

CLEANUP_TARGETS=()

add_cleanup() {
    CLEANUP_TARGETS+=("$1")
}

cleanup() {
    echo "Running cleanup..." >&2
    for target in "${CLEANUP_TARGETS[@]:-}"; do
        rm -rf "$target"
        echo "Removed: $target" >&2
    done
}
trap cleanup EXIT

# Create and track temp resources
TMPDIR_WORK=$(mktemp -d /tmp/work.XXXXXX)
add_cleanup "$TMPDIR_WORK"

TMPFILE_LOG=$(mktemp /tmp/run.XXXXXX.log)
add_cleanup "$TMPFILE_LOG"

echo "Working in $TMPDIR_WORK" | tee "$TMPFILE_LOG"
touch "$TMPDIR_WORK/output.txt"
echo "Step complete."

ERR 트랩 — 실패 포착

ERR 의사 신호는 단순 명령이 0이 아닌 종료 상태를 반환한 후 실행됩니다. 단, 셸 옵션 set -e (errexit)가 활성화되어 있거나 해당 명령이 if, while, ||/&& 복합 명령 안에 있지 않아야 합니다.

ERR 트랩은 다음과 같은 용도로 사용하십시오.

  • $LINENO 및 $BASH_COMMAND를 사용하여 실패한 줄을 기록합니다.
  • EXIT 트랩이 실행되기 전에 롤백 로직을 실행합니다.
  • 구조화된 오류 메시지를 표준 오류로 출력합니다.

중요: set -E (errtrace)를 명시적으로 실행하여 함수가 호출한 셸의 ERR 트랩을 상속하도록 하지 않으면 함수 안에서는 ERR 트랩이 실행되지 않습니다.

#!/usr/bin/env bash
set -eEuo pipefail

on_error() {
    local exit_code=$?
    local line=$1
    echo "ERROR: command failed with exit code $exit_code at line $line" >&2
    echo "  Command: $BASH_COMMAND" >&2
}
trap 'on_error $LINENO' ERR

echo "Starting task..."
cp /nonexistent/file /tmp/   # This will fail
echo "This line is never reached."

INT 트랩 — 우아한 Ctrl+C 처리

Ctrl+C를 누르면 포그라운드 프로세스 그룹에 SIGINT가 전송됩니다. 트랩이 없으면 Bash가 즉시 종료되어 작업 일부가 남을 수 있습니다.

INT 트랩을 등록하면 다음을 수행할 수 있습니다.

  • 사용자가 이해하기 쉬운 취소 메시지를 출력합니다.
  • EXIT 트랩에 넘기기 전에 필요한 중간 롤백을 수행합니다.
  • 의미 있는 상태 코드로 종료합니다(130은 SIGINT의 관례적인 코드이며 128 + 2입니다).

INT 처리기가 끝난 후 exit 130을 호출하여 올바른 종료 코드를 전달하십시오. 그러면 EXIT 트랩이 자동으로 실행됩니다.

#!/usr/bin/env bash
set -euo pipefail

TMPFILE=$(mktemp /tmp/demo.XXXXXX)

cleanup() {
    rm -f "$TMPFILE"
    echo "Temp file removed." >&2
}

on_interrupt() {
    echo "" >&2
    echo "Caught SIGINT — cancelling gracefully." >&2
    exit 130   # EXIT trap (cleanup) runs automatically after this
}

trap cleanup EXIT
trap on_interrupt INT

echo "Running long task. Press Ctrl+C to cancel."
for i in $(seq 1 10); do
    echo "Step $i/10..."
    sleep 1
done
echo "All steps complete."

EXIT, ERR, INT 트랩 결합

실제 운영 스크립트에서는 일반적으로 모든 종료 경로를 다루기 위해 세 트랩을 모두 함께 등록합니다.

  • EXIT — 항상 실행되며 파일을 정리합니다.
  • ERR — 실패한 명령과 줄 번호를 기록합니다.
  • INT — 취소 메시지를 출력하고 코드 130으로 종료합니다.

EXIT는 항상 마지막에 실행되므로 정리 로직을 한 곳에만 두면 됩니다. ERR 및 INT 처리기는 기록과 상태 설정에 집중한 다음 exit을 호출하여 실제 정리를 EXIT에 위임할 수 있습니다.

맨 위에서 set -eEuo pipefail을 사용하면 함수 안의 오류도 ERR을 실행하고 pipefail이 파이프라인 내부의 실패를 포착합니다.

#!/usr/bin/env bash
set -eEuo pipefail

TMPFILE=$(mktemp /tmp/combined.XXXXXX)
ROLLBACK_NEEDED=false

cleanup() {
    if [[ "$ROLLBACK_NEEDED" == true ]]; then
        echo "Rolling back partial changes..." >&2
    fi
    rm -f "$TMPFILE"
    echo "Cleanup done." >&2
}

on_error() {
    ROLLBACK_NEEDED=true
    echo "ERR at line $1: $BASH_COMMAND" >&2
}

on_interrupt() {
    echo "Interrupted by user." >&2
    exit 130
}

trap cleanup       EXIT
trap 'on_error $LINENO' ERR
trap on_interrupt  INT

echo "hello" > "$TMPFILE"
echo "Script finished successfully."

트랩 동적 재설정 및 비활성화

때로는 스크립트 실행 중간에 트랩을 수정해야 합니다. 예를 들어 중요한 구역이 완료된 후 한 번만 정리하여 이후의 정상 작업에서 불필요한 롤백이 실행되지 않도록 할 수 있습니다.

  • trap - SIGNAL은 신호를 내장된 기본 동작으로 재설정합니다.
  • trap '' SIGNAL은 신호를 완전히 무시합니다(프로세스가 해당 신호로 종료되지 않습니다).
  • 언제든 새 처리기를 다시 등록할 수 있으며 마지막 trap 호출이 적용됩니다.

일반적인 방식은 위험한 작업이 성공한 후 EXIT 트랩을 변경하여 롤백 처리기를 간단한 정리 처리기로 전환하는 것입니다.

#!/usr/bin/env bash
set -euo pipefail

TMPFILE=$(mktemp /tmp/staged.XXXXXX)

rollback() {
    echo "ROLLBACK: removing $TMPFILE" >&2
    rm -f "$TMPFILE"
}

cleanup_only() {
    echo "CLEANUP: removing $TMPFILE" >&2
    rm -f "$TMPFILE"
}

# Start with rollback in case something fails during the risky phase
trap rollback EXIT

echo "Performing risky operation..."
echo "critical data" > "$TMPFILE"
# ... imagine more risky steps here ...

# Risky phase succeeded — switch to simple cleanup
trap cleanup_only EXIT

echo "Risky phase done. Now doing safe finalization."
cp "$TMPFILE" /tmp/staged_result.txt
echo "All done."

트랩을 통한 종료 코드 전달

미묘하지만 중요한 함정이 있습니다. 정리 함수에 실패할 수 있는 명령이 포함되어 있으면 스크립트의 최종 종료 코드가 덮어써질 수 있습니다. 원래 종료 코드를 명시적으로 보존하십시오.

트랩 처리기 안에서 $?에는 트랩을 발생시킨 종료 코드가 들어 있습니다. 다른 명령이 이 값을 변경하기 전에 처리기의 첫 줄에서 캡처하십시오.

#!/usr/bin/env bash
set -euo pipefail

TMPFILE=$(mktemp /tmp/exitcode.XXXXXX)

cleanup() {
    local original_exit=$?   # capture BEFORE any other command
    echo "Cleaning up (original exit: $original_exit)" >&2
    rm -f "$TMPFILE"
    # Exit with the original code so callers see the real result
    exit "$original_exit"
}
trap cleanup EXIT

echo "Doing work..."
echo "data" > "$TMPFILE"

# Simulate failure
if [[ ! -f /tmp/required_marker ]]; then
    echo "Required marker missing!" >&2
    exit 2
fi

echo "Done."

함수와 서브셸에서의 트랩

올바른 스크립트를 작성하려면 트랩의 상속을 이해하는 것이 중요합니다.

  • 함수는 같은 셸에서 실행되므로 트랩을 상속합니다. 단, set -E (errtrace)가 활성화된 경우에만 ERR이 함수로 전파됩니다.
  • 서브셸(( ... ))은 부모 트랩의 복사본으로 시작하지만 서브셸 안의 변경 사항은 부모에 영향을 주지 않습니다.
  • 백그라운드 작업(cmd &)은 서브셸이므로 부모의 INT/TERM 트랩을 상속하지 않습니다(기본 신호 처리를 사용합니다).

실용적인 규칙은 트랩 등록을 주 스크립트 본문에 두고, ERR을 함수로 전파해야 할 때 set -E를 사용하며, &를 통한 트랩 상속에 절대 의존하지 않는 것입니다.

#!/usr/bin/env bash
set -eEuo pipefail   # -E = errtrace: ERR propagates into functions

on_error() {
    echo "ERR in function or main at line $1" >&2
}
trap 'on_error $LINENO' ERR

risky_function() {
    echo "Inside risky_function"
    ls /nonexistent_path   # triggers ERR — works because of set -E
}

# Subshell: has its own copy; changes don't affect parent
(
    trap '' ERR   # disable ERR only inside subshell
    ls /nonexistent_path 2>/dev/null || true
    echo "Subshell completed without triggering parent ERR"
)

risky_function

실전 방식: 원자적 파일 교체

대표적인 방어적 Bash 방식은 원자적 파일 교체입니다. 임시 파일에 쓴 다음 해당 파일을 제자리로 이름 변경합니다. 이름 변경 전에 무엇인가 실패하면 원본은 그대로 유지됩니다. 트랩을 사용하면 이 방식을 더욱 안전하게 만들 수 있습니다.

단계:

  1. 대상과 같은 파일 시스템에 임시 파일을 만듭니다(mv가 원자적으로 실행되도록 하기 위해서입니다).
  2. 일찍 종료할 경우 임시 파일을 제거하도록 EXIT 트랩을 등록합니다.
  3. 새 내용을 작성하고 검증합니다.
  4. 원자적으로 이름을 변경합니다(mv). 이제야 원본이 교체됩니다.
  5. EXIT 트랩은 임시 파일이 아직 존재할 때만 제거합니다(성공적인 mv 후에는 임시 파일이 사라집니다).
#!/usr/bin/env bash
set -euo pipefail

DEST="/tmp/important_config.conf"
TMPFILE=$(mktemp "$(dirname "$DEST")/.tmp.XXXXXX")

cleanup() {
    rm -f "$TMPFILE"   # no-op if mv already moved it
}
trap cleanup EXIT

# Write new content to temp file
cat > "$TMPFILE" <<'EOF'
[settings]
version=2
mode=production
EOF

# Validate before replacing
if ! grep -q 'version=' "$TMPFILE"; then
    echo "Validation failed — aborting replacement" >&2
    exit 1
fi

# Atomic rename — DEST is replaced only here
mv "$TMPFILE" "$DEST"
echo "Config updated atomically: $DEST"

확인 문제: ERR 트랩 상속

Bash에서 함수와 함께 사용할 때 ERR 트랩이 어떻게 동작하는지 이해했는지 확인해 보십시오.

복습: 정리와 신호를 위한 트랩 처리기

이 단원에서는 트랩 처리기를 통해 Bash 스크립트의 복원력을 높이는 방법을 배웠습니다.

  • EXIT는 보편적인 안전망입니다. 임시 리소스를 만든 직후 등록하고, 원래 종료 코드를 보존하기 위해 항상 먼저 $?를 캡처하십시오.
  • ERR을 사용하면 $LINENO 및 $BASH_COMMAND로 실패를 기록할 수 있습니다. 함수가 이를 상속하도록 set -E를 사용하십시오.
  • INT는 Ctrl+C를 우아하게 처리합니다. 메시지를 출력하고 코드 130으로 종료하여 EXIT가 정리를 수행하도록 하십시오.
  • 임시 리소스를 배열에 모은 다음 하나의 정리 함수에서 모두 제거하십시오.
  • trap - SIGNAL로 재설정하고 trap '' SIGNAL로 신호를 동적으로 무시하십시오.
  • 원자적 이름 변경 방식(mktemp → 작성 → 검증 → mv)을 EXIT 트랩과 함께 사용하면 일부만 작성된 내용이 대상 파일을 손상시키지 않도록 보장할 수 있습니다.

set -eEuo pipefail과 적절한 위치에 배치한 트랩을 결합하면 모든 운영 환경의 Bash 스크립트를 위한 견고한 방어 기반을 마련할 수 있습니다.

자주 묻는 질문

“정리 및 신호 처리를 위한 트랩 핸들러” 강의는 무료인가요?

네 — “정리 및 신호 처리를 위한 트랩 핸들러” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 DevOps Bootcamp 강의 전체를 잠금 해제할 수 있습니다. DevOps Bootcamp 강의에는 총 4개의 강의가 포함되어 있습니다.

“정리 및 신호 처리를 위한 트랩 핸들러”에서 뭘 배우나요?

EXIT, ERR 및 INT 트랩을 등록하여 임시 파일을 삭제하고 부분적으로 수행된 작업을 안정적으로 되돌립니다. 브라우저에서 직접 실행하는 실습 코드로 DevOps Bootcamp을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

DevOps Bootcamp을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 DevOps Bootcamp은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.

“정리 및 신호 처리를 위한 트랩 핸들러” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 DevOps Bootcamp 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 DevOps Bootcamp 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. set -euo pipefail을 활용한 엄격 모드
  2. 정리 및 신호 처리를 위한 트랩 핸들러
  3. 안전한 임시 파일 및 잠금 디렉터리
  4. 멱등적 스크립트와 지수 백오프 재시도 로직
← DevOps Bootcamp(으)로 돌아가기