셸 스크립팅 · 견고한 스크립트 · 실습
견고한 스크립트 작성하기
목표
운영 서버에 올려도 되는 스크립트의 조건 - 실패를 숨기지 않고, 뒷정리를 보장하고, 두 번 돌아도 안전한 - 을 하나씩 구현합니다.
왜 중요한가
셸은 기본적으로 관대합니다. 없는 변수는 빈 문자열로 넘어가고, 파이프 중간의 실패는 마지막 명령이 성공하면 묻히고, 스크립트가 죽어도 임시 파일은 남습니다. 이 관대함이 "매일 성공으로 보고되던 백업이 사실 0바이트였다" 같은 사고를 만듭니다. set -euo pipefail 은 문제를 발견 지점에서 멈춰 세우는 장치이고, trap ... EXIT 는 어떤 경로로 끝나든 뒷정리가 돌게 하는 장치입니다. 두 개는 짝으로 써야 의미가 있습니다.
단계
1. /root/robust/strict.sh 를 만드세요. 맨 앞에 set -euo pipefail 을 넣고, 인자를 하나 받아 그대로 출력합니다. strict.sh hello 는 hello 를 출력하고 0 으로, 인자 없이 실행하면 0이 아닌 코드로 끝나야 합니다.
2. /root/robust/pipe.sh 를 만드세요. 인자가 ok 면 성공하는 파이프라인을, broken 이면 앞 단계가 실패하는 파이프라인을 실행합니다. broken 일 때 종료 코드가 0이 아니어야 합니다.
3. /root/robust/tmpwork.sh 를 만드세요. mktemp 로 임시 파일을 만들어 그 경로를 표준출력에 한 줄 출력하고, 종료할 때 trap 으로 반드시 지웁니다. 인자로 fail 을 주면 실패로 끝나되 그때도 임시 파일이 남으면 안 됩니다.
4. /root/robust/once.sh 를 만드세요. 실행하면 약 3초간 작업하고 0 으로 끝납니다. 이미 실행 중일 때 다시 실행하면 already running 을 알리고 종료 코드 9 로 끝나야 합니다. 앞 실행이 끝난 뒤에는 다시 정상 실행돼야 합니다.
5. /root/robust/count.sh <디렉터리> 를 만드세요. 그 디렉터리 바로 아래의 일반 파일 개수만 출력합니다. 디렉터리 경로와 파일 이름 모두에 공백이 있어도 정확해야 하고, 인자가 없으면 0이 아닌 코드로 끝나야 합니다.
6. /root/robust/backup.sh <원본디렉터리> <결과파일> 을 만드세요.
- 인자가 없으면 표준에러에
usage를 포함한 안내를 내고 종료 코드64 - 원본 경로가 없으면 종료 코드
66 - 정상이면 하위 디렉터리까지 포함해 tar.gz 를 만들고 종료 코드
0
7. /root/robust/retry.sh <횟수> <명령...> 을 만드세요. 명령이 실패하면 최대 그 횟수만큼 재시도하되, 시도 사이에 최소 1초는 쉬고, 성공하면 즉시 멈춥니다. 매 시도마다 attempt 라는 단어가 들어간 로그를 남깁니다.
8. /root/robust/audit.sh <스크립트경로> 를 만드세요. 대상 스크립트에 셔뱅과 엄격 모드 선언이 있는지 검사해 strict=yes|no 와 shebang=yes|no 두 줄을 출력합니다. 둘 다 yes 면 종료 코드 0, 아니면 0이 아닌 코드. 파일이 없어도 0이 아닌 코드여야 합니다.
참고
trap핸들러 맨 앞에서local rc=$?로 종료 코드를 붙잡고 마지막에exit "$rc"로 되돌려주지 않으면 트랩이 종료 코드를 삼킵니다.find "$d" -maxdepth 1 -type f로 최상위 일반 파일만 셀 수 있습니다.- 흔한 실수 1: 4번에서 잠금 파일만 만들고 지우지 않으면 다음 실행이 영원히 막힙니다.
- 흔한 실수 2: 7번에서
$*로 명령을 다시 실행하면 공백이 든 인자가 깨집니다.
단계 8개
- 엄격 모드 켜기
- 파이프라인 실패 전파
- 임시 파일을 반드시 지우기
- 중복 실행 막기
- 공백이 든 경로 안전하게 다루기
- 사용법과 종료 코드 규약
- 재시도 헬퍼
- 스크립트 감사 도구