ЁЯЪи рдзрдбрд╛ 08 тАФ Errors рдЖрдгрд┐ safety: рдЖрдЧреАрдЪреА рддрд╛рд▓реАрдо
ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 08 ┬╖ рдкреБрдвреЗ: lesson-09-processes-jobs
ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ
рдзрдбреЗ 01тАУ08. Strict mode, traps, temp files, dry runs рдЖрдгрд┐ linter тАФ рдХреЛрдгреА рд▓рдХреНрд╖ рджреЗрдд рдирд╕рддрд╛рдирд╛рд╣реА script рдЪрд╛рд▓рд╡рдгреЗ рд╕реБрд░рдХреНрд╖рд┐рдд рдХрд░рдгрд╛рд▒реНрдпрд╛ рдкрд╛рдЪ рд╕рд╡рдпреА.
- bin/school.sh тАФ
set -euo pipefail,mktemp+trap тАж EXIT, рдЖрдзреА рд▓рд┐рд╣рд╛-рдордЧ-mv - bin/backup.sh тАФ dry runs рд╕рд╛рдареА
run(),trapрдиреЗ рд╕реЛрдбрд▓реЗ рдЬрд╛рдгрд╛рд░реЗ lock, рди рд╡рд╛рдЪрддрд╛ рдпреЗрдгрд╛рд▒реНрдпрд╛ archive рд╡рд░die
ЁЯзТ 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
тЭУ рдХрд╛рдп
set -efail рд╣реЛрдгрд╛рд▒реНрдпрд╛ command рд╡рд░ exit тАФ рдкрдгif,while,&&/||рд╕рд╛рдЦрд│реНрдпрд╛, рдХрд┐рдВрд╡рд╛ condition рдордзреНрдпреЗ рдмреЛрд▓рд╛рд╡рд▓реЗрд▓реНрдпрд╛ function рдЪреНрдпрд╛ рдЖрдд рдирд╛рд╣реА.set -uunset variable рдореНрд╣рдгрдЬреЗ error.set -o pipefailрдХреЛрдгрддрд╛рд╣реА рдЯрдкреНрдкрд╛ fail рдЭрд╛рд▓рд╛ рддрд░ pipe fail.trap 'cleanup' EXITрдкреНрд░рддреНрдпреЗрдХ exit рд╡рд░ рдЪрд╛рд▓рддреЛ;ERR,INT,TERMрд╕реБрджреНрдзрд╛.- рдХрдЪреНрдЪреНрдпрд╛ рдХрд╛рдорд╛рд╕рд╛рдареА
mktemp/mktemp -d; рддрд┐рдереЗ рд▓рд┐рд╣рд╛, рдордЧmvтАФ рд╡рд╛рдЪрдгрд╛рд▒реНрдпрд╛рдВрдирд╛ рдХрдзреАрдЪ рдЕрд░реНрдзрд╡рдЯ рд▓рд┐рд╣рд┐рд▓реЗрд▓реА file рджрд┐рд╕рдд рдирд╛рд╣реА. - рдЕрдкрдпрд╢ рдЪрд╛рд▓рдгрд╛рд░ рдЕрд╕реЗрд▓ рддреЗрд╡реНрд╣рд╛
|| true; рдХреЛрдгрддреНрдпрд╛рд╣реАrm -rf "$VAR/"рдЖрдзреА${VAR:?}. DRY_RUN=1: рдЪрд╛рд▓рд╡рдгреНрдпрд╛рдРрд╡рдЬреА log рдХрд░рдгрд╛рд░рд╛run()wrapper.shellcheck script.sh: quoting рдЪрд╛ рдкреНрд░рддреНрдпреЗрдХ рд╕рд╛рдкрд│рд╛ рдУрд│рдЦрдгрд╛рд░рд╛ linter.
ЁЯдФ рдХрд╛
рджреЗрдЦрд░реЗрдЦреАрд╢рд┐рд╡рд╛рдп рдЪрд╛рд▓рдгрд╛рд▒реНрдпрд╛ 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 рддреБрдореНрд╣рд╛рд▓рд╛ рдХреБрдареЗ рд╡рд╛рдЪрд╡рдгрд╛рд░ рдирд╛рд╣реА рддреА рдПрдХ рдЬрд╛рдЧрд╛
рддреБрдореНрд╣рд╛рд▓рд╛ рдорд╛рд╣реАрдд рдЖрд╣реЗ.
тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛
ifрдЪреНрдпрд╛ рдЖрдд рдХрд┐рдВрд╡рд╛||рдирдВрддрд░set -eрд╡рд░ рд╡рд┐рд╢реНрд╡рд╛рд╕ рдареЗрд╡рдгреЗ. рдЕрдкрдпрд╢рд╛рдЪрд╛ рдорд╛рд░реНрдЧ test рдХрд░рд╛.- double quotes рдЕрд╕рд▓реЗрд▓рд╛
trapvariables рдЦреВрдк рд▓рд╡рдХрд░ expand рдХрд░рддреЛ. рдореБрджреНрджрд╛рдо рддрд╕реЗ рдХрд░рд╛рдпрдЪреЗ рдирд╕реЗрд▓ рддрд░ trap string single-quote рдХрд░рд╛. DIRрд░рд┐рдХрд╛рдорд╛ рдЕрд╕реВ рд╢рдХрддреЛ рддрд┐рдереЗrm -rf "$DIR/"*."${DIR:?}".
ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: fail рдЭрд╛рд▓реЗрд▓реНрдпрд╛
cdрдирдВрддрд░рд╣реА рдЪрд╛рд▓реВ рд░рд╛рд╣реВрди рдЪреБрдХреАрдЪреЗ release delete рдХрд░рдгрд╛рд░рд╛ deploy; рд░рд┐рдХрд╛рдореНрдпрд╛ archive рд╕рд╣ "рдпрд╢рд╕реНрд╡реА" рдЭрд╛рд▓реЗрд▓рд╛ backup тАФ рджреЛрдиреНрд╣реА рдпрд╛ рдзрдбреНрдпрд╛рдЪреНрдпрд╛ рджрд╣рд╛ рдУрд│реАрдВрдиреА рдЯрд╛рд│рддрд╛ рдЖрд▓реЗ рдЕрд╕рддреЗ.
тПня╕П рдкреБрдвреЗ
рдзрдбрд╛ 09 тАФ processes рдЖрдгрд┐ jobs: рдЗрдорд╛рд░рддреАрдд рдХреЛрдг рдЖрд╣реЗ, рдЖрдгрд┐ рддреНрдпрд╛рдВрдирд╛ рдмрд╛рд╣реЗрд░ рдЬрд╛рдпрд▓рд╛ рдХрд╕реЗ рд╕рд╛рдВрдЧрд╛рдпрдЪреЗ.