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

실전 셸 스크립트: 백업, 배포, 상태 점검

~13 min · practical, backup, deploy

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

검토 가능한 셸 스크립트의 모양

운영에 쓰는 셸 스크립트는 인터프리터, 입력, 상태 변경, 작은 함수, 주 흐름, 실패 보고, 정리의 한계가 눈에 보여야 해. 아래 코드는 출발점일 뿐이므로 실제 경로와 권한, 실패 조건을 확인하지 않은 채 운영 명령으로 복사하면 안 돼.

backup.sh: 날짜별 보관 경로로 동기화

#!/usr/bin/env bash
set -euo pipefail
src="${1:-$HOME}"
dest="${BACKUP_ROOT:-/Volumes/backup}/$(date +%Y/%m/%d)"
mkdir -p "$dest"
rsync -a --dry-run --itemize-changes --exclude='.cache' "$src/" "$dest/"
printf 'dry run을 검토한 뒤 --dry-run 없이 다시 실행해\n'
# 대상이 검증된 폐기 가능 mirror일 때만 --delete를 추가해

--itemize-changes는 어떤 항목이 왜 달라지는지 보여 줘. --delete는 단순 동기화 옵션이 아니라 대상에서 파일을 지우므로, 목적지가 정확한 미러이고 복구 경로가 있을 때만 별도로 승인해.

deploy.sh: 테스트를 통과한 뒤 push

#!/usr/bin/env bash
set -euo pipefail
log() { printf '%(%H:%M:%S)T %s\n' -1 "$*"; }
trap 'log "deploy failed at line $LINENO"' ERR
log 'running tests'
./test.sh
log 'pushing'
git push origin main
log 'done'

테스트 실패가 push를 막는 흐름과 실패한 줄을 남기는 트랩이 한눈에 보여야 해. 실제 배포라면 브랜치, 원격, 승인 주체도 이 스크립트 밖의 운영 계약으로 고정해.

daily-check.sh: 상태 점검 게이트

#!/usr/bin/env bash
set -u
set -o pipefail
fail=0
check_http() { curl --fail --silent --show-error --max-time 10 https://api.example/health; }
check_worker() { pgrep -x my-worker >/dev/null; }
check_disk() { df -P / | awk 'NR==2 { exit !($5+0 < 90) }'; }
for name in http worker disk; do
  if "check_${name}"; then
    printf 'OK %s\n' "$name"
  else
    printf 'FAIL %s\n' "$name" >&2
    fail=1
  fi
done
exit "$fail"

HTTP 검사에는 시간 제한을 두고, 프로세스 검사는 넓은 부분 문자열 대신 정확한 이름을 써. 각 검사의 실패를 모두 모은 뒤 마지막에 하나의 종료 상태로 반환하면 스케줄러가 결과를 판정할 수 있어.

스케줄링 전에 실행 주인을 정해

작업을 누가 시작하고 멈추며 재시도하는지, 어떤 인터프리터·입력·출력·로그·재시도 정책을 쓰는지 함께 적어 둬. 읽기 좋은 파일만으로는 운영 가능한 작업이 되지 않아.

이름에 목적과 수명을 담아

파일 이름과 머리말에 무엇을 지키는 작업인지, 일회성인지 계속 운영할 것인지 남겨. 날짜만 붙인 복사본을 늘리기보다 하나의 소유자, 실행 경로, 교체 절차를 정하면 나중에 안전하게 멈출 수 있어.

예제와 운영 명령 사이에 검증을 둬

소스와 목적지, 권한, 삭제 동작을 먼저 출력하고 dry-run 결과를 사람이 읽어. dry-run은 장식이 아니라 이번 대상이 맞다는 증거야. 같은 인자로 본 실행을 할 때도 대상이 바뀌지 않았는지 다시 확인해.

eval 대신 함수와 인자 배열

명령을 문자열로 저장해 eval하면 데이터가 셸 문법으로 다시 해석돼. 고정된 검사는 이름 있는 함수로 만들고 동적인 값은 인용한 배열로 보존해 직접 호출해. 그래야 공백과 사용자 입력이 명령 구조를 바꾸지 않아.

Code

재사용 가능한 헤더 블록·bash
#!/usr/bin/env bash
# 설명 예시: 홈을 NAS에 매주 백업
set -euo pipefail
IFS=$'\n\t'
HERE="$(cd "$(dirname "$0")" && pwd)"
log() { printf '%(%H:%M:%S)T %s\n' -1 "$*" >&2; }
die() { log "FATAL: $*"; exit 1; }
trap 'die "failed at line $LINENO"' ERR
# 실제 작업은 아래에서 실행
log 'starting'

External links

Exercise

검토한 재사용 헤더를 ~/bin/_template.sh에 저장하고 그 사본으로 작은 backup.sh를 작성해. 시험용 notes 디렉터리를 날짜가 붙은 백업 경로로 rsync한 뒤 파일 수와 상태를 검증하고, set -euo pipefail 아래에서도 실패가 조용히 숨지 않는지 확인해.

Progress

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

댓글 0

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

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