ЁЯПл The SchoolтА║ЁЯз╣ Shell scriptingтА║ЁЯЪи рдзрдбрд╛ 08 тАФ Errors рдЖрдгрд┐ safety: рдЖрдЧреАрдЪреА рддрд╛рд▓реАрдо
ЁЯЦ╝я╕П See the drawing + lab ЁЯПа Course home ЁЯМ┐ Branch on GitHub тЬПя╕П View source
ЁЯЦ╝я╕П рдЖрдХреГрддреА рдЖрдгрд┐ labThe drawing + lab рдкреВрд░реНрдг рдкрд╛рдирд╛рд╡рд░ рдЙрдШрдбрд╛ тЖЧOpen full page тЖЧ

ЁЯЪи рдзрдбрд╛ 08 тАФ Errors рдЖрдгрд┐ safety: рдЖрдЧреАрдЪреА рддрд╛рд▓реАрдо

ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 08 ┬╖ рдкреБрдвреЗ: lesson-09-processes-jobs


ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ

рдзрдбреЗ 01тАУ08. Strict mode, traps, temp files, dry runs рдЖрдгрд┐ linter тАФ рдХреЛрдгреА рд▓рдХреНрд╖ рджреЗрдд рдирд╕рддрд╛рдирд╛рд╣реА script рдЪрд╛рд▓рд╡рдгреЗ рд╕реБрд░рдХреНрд╖рд┐рдд рдХрд░рдгрд╛рд▒реНрдпрд╛ рдкрд╛рдЪ рд╕рд╡рдпреА.

ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ

рдПрдЦрд╛рджреЗ рджрд╛рд░ рдЙрдШрдбрдд рдирд╕рддрд╛рдирд╛рд╣реА рдХрд╛рдо рдЪрд╛рд▓реВ рдареЗрд╡рдгрд╛рд░рд╛ рдХреЗрдЕрд░рдЯреЗрдХрд░ рд╢реЗрд╡рдЯреА рдЪреБрдХреАрдЪрд╛ рдордЬрд▓рд╛ рдкреБрд╕рдд рдмрд╕рддреЛ. Strict mode рддреНрдпрд╛рд▓рд╛ рд╕рд╛рдВрдЧрддреЛ: fail рд╣реЛрдгрд╛рд▒реНрдпрд╛ рдкрд╣рд┐рд▓реНрдпрд╛рдЪ рдЧреЛрд╖реНрдЯреАрд╡рд░ рдерд╛рдВрдм (-e), рдЕрд╕реНрддрд┐рддреНрд╡рд╛рдд рдирд╕рд▓реЗрд▓рд╛ name tag рд╡рд╛рдкрд░рд╛рдпрд▓рд╛ рдирдХрд╛рд░ рджреЗ (-u), рдЖрдгрд┐ pipe рдЪреНрдпрд╛ рдордзреЗрдЪ рдЭрд╛рд▓реЗрд▓реЗ рдЕрдкрдпрд╢ рд▓рдХреНрд╖рд╛рдд рдШреЗ (-o pipefail). trap рдореНрд╣рдгрдЬреЗ рдЖрдЧреАрдЪреНрдпрд╛ рддрд╛рд▓рдореАрдЪреЗ рдХрд╛рд░реНрдб: рдХрд╛рд╣реАрд╣реА рд╣реЛрд╡реЛ тАФ рдпрд╢, error, Ctrl-C тАФ temp files рдЖрд╡рд░реВрди рдареЗрд╡ рдЖрдгрд┐ lock рд╕реЛрдб. dry run рдореНрд╣рдгрдЬреЗ рд░рдВрдЧреАрдд рддрд╛рд▓реАрдо: рдХрд╛рдп рдХрд░рд╢реАрд▓ рддреЗ рд╕рд╛рдВрдЧ, рдХрд╢рд╛рд▓рд╛рд╣реА рд╣рд╛рдд рд▓рд╛рд╡реВ рдирдХреЛрд╕.

ЁЯЧ║я╕П рдЖрдХреГрддреА

flowchart LR
  S["set -euo pipefail"] --> T["tmp=$(mktemp)<br/>trap 'rm -f \"$tmp\"' EXIT"] --> W["write to $tmp"] --> M["mv $tmp target (atomic)"]
  X["any failure / Ctrl-C"] -.-> T

тЭУ рдХрд╛рдп

ЁЯдФ рдХрд╛

рджреЗрдЦрд░реЗрдЦреАрд╢рд┐рд╡рд╛рдп рдЪрд╛рд▓рдгрд╛рд▒реНрдпрд╛ scripts рдкрд╣рд╛рдЯреЗ 2 рд╡рд╛рдЬрддрд╛, рдХреЛрдгреА рдкрд╛рд╣рдд рдирд╕рддрд╛рдирд╛ fail рд╣реЛрддрд╛рдд. Strict mode рдЧреБрдкрдЪреВрдк рдЕрд░реНрдзрд╡рдЯ рд░рд╛рд╣рд┐рд▓реЗрд▓реНрдпрд╛ рдХрд╛рдорд╛рд▓рд╛ рдореЛрдареНрдпрд╛рдиреЗ рдерд╛рдВрдмрдгреНрдпрд╛рдд рдмрджрд▓рддреЛ; traps рдкрд╕рд╛рд░рд╛ рд╕рд╛рдареВ рджреЗрдд рдирд╛рд╣реАрдд; dry runs рдореБрд│реЗ production рдордзрд▓реНрдпрд╛ рд╡рд┐рдзреНрд╡рдВрд╕рдХ рдмрджрд▓рд╛рдЪрд╛ рд╕реБрд░рдХреНрд╖рд┐рддрдкрдгреЗ рд╕рд░рд╛рд╡ рдХрд░рддрд╛ рдпреЗрддреЛ.

ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)

school.sh рдУрд│ 15: strict mode. cmd_grade: tmp=$(mktemp); trap 'rm -f "$tmp"' EXIT; awk тАж > "$tmp" && mv "$tmp" "$REGISTER". backup.sh: run() { [[ "${DRY_RUN:-0}" == 1 ]] && log "would: $*" || "$@"; }, mkdir "$LOCK" || die, trap 'rmdir "$LOCK"' EXIT, tar -tzf "$out" || die.

ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛

DRY_RUN=1 bin/backup.sh --dest /tmp/bk               # the rehearsal: "would: tar тАж", nothing written
ls /tmp/bk 2>/dev/null | wc -l                        # 0
bash -c 'set -u; echo "$REGISTR"'; echo "exit $?"     # the typo is caught
bash -c 'set -o pipefail; false | true'; echo "exit $?"    # 1 тАФ the pipe knows
bash -c 'set -e; if false; then :; fi; echo "still here (set -e is off inside if)"'
bash -c 't=$(mktemp); trap "echo cleanup; rm -f $t" EXIT; echo working; exit 2'; echo "exit $?"
command -v shellcheck && shellcheck bin/school.sh || echo "install shellcheck: brew install shellcheck / apt install shellcheck"

тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ

dry run would: tar тАж log рдХрд░рддреЛ рдЖрдгрд┐ рдХрд╛рд╣реАрд╣реА рдмрдирд╡рдд рдирд╛рд╣реА; unbound variable exit 1; pipefail exit 1; set -e рдЪреА рдУрд│ рддрд░реАрд╣реА рдЫрд╛рдкрд▓реА рдЬрд╛рддреЗ; working, cleanup, рдордЧ exit 2 тАФ trap рдЪрд╛рд▓рд▓рд╛ рдЖрдгрд┐ exit code рдЯрд┐рдХрд▓рд╛.

ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ

рддреБрдореНрд╣реА script рд▓рд╛ рдЕрдкрдпрд╢рд╛рд╡рд░ рдерд╛рдВрдмрд╡реВ рд╢рдХрддрд╛, рдкреНрд░рддреНрдпреЗрдХ exit рд╡рд░ рд╕рд╛рдлрд╕рдлрд╛рдИ рдХрд░рд╛рдпрд▓рд╛ рд▓рд╛рд╡реВ рд╢рдХрддрд╛, рдХреЛрдгрддрд╛рд╣реА рдкрд░рд┐рдгрд╛рдо рди рд╣реЛрддрд╛ рд╕рд░рд╛рд╡ рдХрд░реВ рд╢рдХрддрд╛ тАФ рдЖрдгрд┐ set -e рддреБрдореНрд╣рд╛рд▓рд╛ рдХреБрдареЗ рд╡рд╛рдЪрд╡рдгрд╛рд░ рдирд╛рд╣реА рддреА рдПрдХ рдЬрд╛рдЧрд╛ рддреБрдореНрд╣рд╛рд▓рд╛ рдорд╛рд╣реАрдд рдЖрд╣реЗ.

тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛

ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: fail рдЭрд╛рд▓реЗрд▓реНрдпрд╛ cd рдирдВрддрд░рд╣реА рдЪрд╛рд▓реВ рд░рд╛рд╣реВрди рдЪреБрдХреАрдЪреЗ release delete рдХрд░рдгрд╛рд░рд╛ deploy; рд░рд┐рдХрд╛рдореНрдпрд╛ archive рд╕рд╣ "рдпрд╢рд╕реНрд╡реА" рдЭрд╛рд▓реЗрд▓рд╛ backup тАФ рджреЛрдиреНрд╣реА рдпрд╛ рдзрдбреНрдпрд╛рдЪреНрдпрд╛ рджрд╣рд╛ рдУрд│реАрдВрдиреА рдЯрд╛рд│рддрд╛ рдЖрд▓реЗ рдЕрд╕рддреЗ.

тПня╕П рдкреБрдвреЗ

рдзрдбрд╛ 09 тАФ processes рдЖрдгрд┐ jobs: рдЗрдорд╛рд░рддреАрдд рдХреЛрдг рдЖрд╣реЗ, рдЖрдгрд┐ рддреНрдпрд╛рдВрдирд╛ рдмрд╛рд╣реЗрд░ рдЬрд╛рдпрд▓рд╛ рдХрд╕реЗ рд╕рд╛рдВрдЧрд╛рдпрдЪреЗ.

ЁЯЪи Lesson 08 тАФ Errors & safety: the fire drill

ЁЯУН You are here: Lesson 08 of 12 ┬╖ Next: lesson-09-processes-jobs


ЁЯУж What's in this branch

Lessons 01тАУ08. Strict mode, traps, temp files, dry runs and the linter тАФ the five habits that make a script safe to run unattended.

ЁЯзТ Explain like I'm 5

A caretaker who keeps working after a door will not open ends up mopping the wrong floor. Strict mode tells them: stop at the first thing that fails (-e), refuse to use a name tag that does not exist (-u), and notice a failure in the middle of a pipe (-o pipefail). A trap is the fire drill card: whatever happens тАФ success, error, Ctrl-C тАФ put the temp files away and release the lock. A dry run is the rehearsal: say what you would do, touch nothing.

ЁЯЧ║я╕П Diagram

flowchart LR
  S["set -euo pipefail"] --> T["tmp=$(mktemp)<br/>trap 'rm -f \"$tmp\"' EXIT"] --> W["write to $tmp"] --> M["mv $tmp target (atomic)"]
  X["any failure / Ctrl-C"] -.-> T

тЭУ What

ЁЯдФ Why

Unattended scripts fail at 2 a.m. with nobody watching. Strict mode turns a silent half-done job into a loud stop; traps keep the mess from piling up; dry runs let you rehearse a destructive change in production safely.

ЁЯФз How (in this repo)

school.sh line 15: strict mode. cmd_grade: tmp=$(mktemp); trap 'rm -f "$tmp"' EXIT; awk тАж > "$tmp" && mv "$tmp" "$REGISTER". backup.sh: run() { [[ "${DRY_RUN:-0}" == 1 ]] && log "would: $*" || "$@"; }, mkdir "$LOCK" || die, trap 'rmdir "$LOCK"' EXIT, tar -tzf "$out" || die.

ЁЯзк Try it

DRY_RUN=1 bin/backup.sh --dest /tmp/bk               # the rehearsal: "would: tar тАж", nothing written
ls /tmp/bk 2>/dev/null | wc -l                        # 0
bash -c 'set -u; echo "$REGISTR"'; echo "exit $?"     # the typo is caught
bash -c 'set -o pipefail; false | true'; echo "exit $?"    # 1 тАФ the pipe knows
bash -c 'set -e; if false; then :; fi; echo "still here (set -e is off inside if)"'
bash -c 't=$(mktemp); trap "echo cleanup; rm -f $t" EXIT; echo working; exit 2'; echo "exit $?"
command -v shellcheck && shellcheck bin/school.sh || echo "install shellcheck: brew install shellcheck / apt install shellcheck"

тЬЕ Verify тАФ what you should see

The dry run logs would: tar тАж and creates nothing; unbound variable exit 1; pipefail exit 1; the set -e line still prints; working, cleanup, then exit 2 тАФ the trap ran and the exit code survived.

ЁЯПБ What you just proved

You can make a script stop on failure, clean up on every exit, rehearse without side effects тАФ and you know the one place set -e will not save you.

тЪая╕П Common mistakes

ЁЯПн Why this matters in production: the deploy that continued after a failed cd and deleted the wrong release; the backup that "succeeded" with an empty archive тАФ both prevented by this lesson's ten lines.

тПня╕П Next

Lesson 09 тАФ processes & jobs: who is in the building, and how to ask them to leave.

тЖР Previousfunctions argumentsNext тЖТprocesses jobs

This page is the lesson's README from the lesson-08-errors-safety branch, shown here so the whole School stays on one site. Code files open on GitHub at the same branch.