ERR trap zděděný do command substitution smaže sdílené soubory
import { Aside } from ‘@astrojs/starlight/components’;
Symptom
Sekce “Symptom”Dlouhý automatizační skript (set -Eeuo pipefail, ERR trap s úklidem temp souborů)
deterministicky selže o několik kroků později, než kde je skutečná příčina:
HTTP klient najednou posílá requesty bez session cookies (server vrací redirect
na login), přestože předchozí kroky se stejným cookie jarem fungovaly. V logu není
o úklidu ani řádka.
Root cause
Sekce “Root cause”set -Edědí ERR trap do funkcí i command substitution (subshellů).- Skript má krok, který záměrně očekává selhání příkazu a výstup si ukládá:
Terminál OUT=$(psql … -c "UPDATE chráněná_tabulka …" 2>&1) && RC=0 || RC=$? - Selhání uvnitř
$(...)vystřelí zděděný ERR trap v subshellu. Trap spustí cleanup (rm -ftemp souborů) — ale filesystem je sdílený s rodičem, takže zmizí i soubory, které rodič dál potřebuje (cookie jar, response body, …). 2>&1uvnitř substituce tiše zachytí i výstup trapu do proměnné — v logu se úklid vůbec neobjeví. Rodičovská|| RC=$?větev selhání „ošetří” a skript pokračuje dál s rozbitým prostředím.
Selhání se projeví až u prvního dalšího kroku, který smazané soubory použije — a vypadá jako úplně jiná chyba (ztracená session, chybějící soubor…).
Fix
Sekce “Fix”Odzbrojit trap uvnitř substituce — subshell si nese vlastní trap stav:
OUT=$(trap - ERR; psql … -c "UPDATE chráněná_tabulka …" 2>&1) && RC=0 || RC=$?Jak to najít
Sekce “Jak to najít”- Response trace HTTP klienta:
curl --trace-asciiukážeWARNING: failed to open cookie file— soubor v době requestu neexistoval. - Minimální reprodukce mechanismu:
Terminál bash -c 'set -Eeuo pipefail; J=$(mktemp)trap "rm -f \"$J\"; echo CLEANED" ERROUT=$(false 2>&1) || true[ -e "$J" ] && echo OK || echo "SOUBOR SMAZAN, vystup trapu: $OUT"'
Prevence
Sekce “Prevence”- Idiom
$(trap - ERR; …)pro všechna záměrně selhávající místa; vynutit statickým testem (regrese: každá substituce následovaná|| RC=$?musí začínattrap - ERR;). - Cleanup funkce psát tak, aby smazání souborů bylo výhradně věcí rodiče
(guard
[ "${BASH_SUBSHELL:-0}" = "0" ] || return 0na začátku trapu).