Trap-hanterare för städning och signaler
Registrera EXIT-, ERR- och INT-traps för att pålitligt ta bort temporära filer och rulla tillbaka ofullständigt arbete.
Trap-hanterare för städning och signaler är en gratis lektion i Bemästra Linux-kommandoraden och Bash-skriptning på CoddyKit. Detta är lektion 2 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för Bemästra Linux-kommandoraden och Bash-skriptning, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Bemästra Linux-kommandoraden och Bash-skriptning innehåller totalt 4 lektioner.
Varför trap-hanterare är viktiga
När ett Bash-skript avslutas — normalt, på grund av ett fel eller för att användaren tryckte på Ctrl+C — kan det lämna kvar temporära filer, ofullständigt skrivna data eller ett trasigt tillstånd. Utan städning samlas dessa rester på hög och orsakar problem som är svåra att felsöka.
Trap-hanterare löser detta genom att registrera en funktion eller ett kommando som Bash kör automatiskt när en viss signal eller pseudosignal tas emot.
- EXIT — körs varje gång skriptet avslutas, oavsett orsak
- ERR — körs efter att ett kommando returnerar en avslutskod som inte är noll
- INT — körs när användaren skickar SIGINT (Ctrl+C)
- TERM — körs vid SIGTERM (t.ex. från
kill)
Ett välskrivet skript registrerar dessa fällor allra högst upp, innan något riskfyllt arbete påbörjas.
Syntax för det inbyggda kommandot trap
Det inbyggda kommandot trap registrerar en hanterare för en eller flera signaler eller pseudosignaler. Den allmänna syntaxen är:
trap 'command_or_function' SIGNAL [SIGNAL...]
Viktiga regler:
- Det första argumentet är en citerad sträng med shellkod (eller ett funktionsnamn) som ska köras när signalen utlöses.
- Ni kan ange flera signaler efter hanteraren.
trap '' SIGNALignorerar signalen (tom hanterare).trap - SIGNALåterställer signalen till dess standardbeteende.
Fällor ärvs av funktioner som anropas i samma shell, men inte av subsheller som startas med ( ) eller &.
#!/usr/bin/env bash
# Syntax examples — not a full script
# Register a cleanup function on EXIT
trap cleanup EXIT
# Inline handler for INT and TERM
trap 'echo "Interrupted!"; exit 1' INT TERM
# Ignore SIGHUP
trap '' HUP
# Reset SIGPIPE to default
trap - PIPEEXIT-fällan — ert skyddsnät
EXIT-pseudosignalen är den viktigaste fällan att registrera. Den utlöses när shellet avslutas av vilken orsak som helst: normalt slutförande, exit N, ett fel som inte hanteras eller en signal. Därför passar den utmärkt för att ta bort temporära filer.
Rekommenderad metod:
- Skapa temporära filer med
mktempså att namnet blir unikt och oförutsägbart. - Spara sökvägen i en variabel direkt.
- Registrera EXIT-fällan direkt efter skapandet så att städningen alltid körs.
Skriptets avslutskod bevaras — trap-hanterarens avslutskod ignoreras om ni inte uttryckligen anropar exit i den.
#!/usr/bin/env bash
set -euo pipefail
TMPFILE=$(mktemp /tmp/myapp.XXXXXX)
cleanup() {
echo "Removing temp file: $TMPFILE" >&2
rm -f "$TMPFILE"
}
trap cleanup EXIT
# Do real work
echo "Processing..." > "$TMPFILE"
sort "$TMPFILE" -o "$TMPFILE"
cp "$TMPFILE" /tmp/myapp_result.txt
echo "Done. Result saved."Hantera flera temporära filer och kataloger
Riktiga skript skapar ofta flera temporära resurser — filer, kataloger, FIFO:er och låsfiler. I stället för att hålla reda på var och en separat samlar ni dem i en array och tar bort allt i en enda städfunktion.
Det här mönstret skalar smidigt: varje gång ni skapar en ny temporär resurs lägger ni till den i arrayen. EXIT-fällan hanterar alltid hela listan, oavsett var skriptet avslutas.
#!/usr/bin/env bash
set -euo pipefail
CLEANUP_TARGETS=()
add_cleanup() {
CLEANUP_TARGETS+=("$1")
}
cleanup() {
echo "Running cleanup..." >&2
for target in "${CLEANUP_TARGETS[@]:-}"; do
rm -rf "$target"
echo "Removed: $target" >&2
done
}
trap cleanup EXIT
# Create and track temp resources
TMPDIR_WORK=$(mktemp -d /tmp/work.XXXXXX)
add_cleanup "$TMPDIR_WORK"
TMPFILE_LOG=$(mktemp /tmp/run.XXXXXX.log)
add_cleanup "$TMPFILE_LOG"
echo "Working in $TMPDIR_WORK" | tee "$TMPFILE_LOG"
touch "$TMPDIR_WORK/output.txt"
echo "Step complete."ERR-fällan — fånga fel
Pseudosignalen ERR utlöses efter att ett enkelt kommando returnerar en avslutskod som inte är noll, förutsatt att shell-alternativet set -e (errexit) är aktivt eller att kommandot inte finns inuti ett if, en while eller ett sammansatt kommando med ||/&&.
Använd ERR-fällan för att:
- Logga vilken rad som misslyckades med hjälp av
$LINENOoch$BASH_COMMAND. - Starta återställningslogik innan EXIT-fällan körs.
- Skriva strukturerade felmeddelanden till standardfelet.
Viktigt: ERR-fällor utlöses inte i funktioner om ni inte uttryckligen kör set -E (errtrace), så att funktioner ärver ERR-fällan från det anropande shellet.
#!/usr/bin/env bash
set -eEuo pipefail
on_error() {
local exit_code=$?
local line=$1
echo "ERROR: command failed with exit code $exit_code at line $line" >&2
echo " Command: $BASH_COMMAND" >&2
}
trap 'on_error $LINENO' ERR
echo "Starting task..."
cp /nonexistent/file /tmp/ # This will fail
echo "This line is never reached."INT-fällan — hantera Ctrl+C elegant
När ni trycker på Ctrl+C skickas SIGINT till processgruppen i förgrunden. Utan en fälla avslutas Bash omedelbart, vilket kan lämna efter sig ofullständigt arbete.
Genom att registrera en INT-fälla kan ni:
- Skriva ut ett användarvänligt meddelande om avbrytandet.
- Utföra eventuell mellanliggande återställning innan ni överlåter till EXIT-fällan.
- Avsluta med en meningsfull statuskod (
130är den konventionella koden för SIGINT:128 + 2).
När INT-hanteraren är klar anropar ni exit 130 för att vidarebefordra rätt avslutskod. EXIT-fällan körs sedan automatiskt.
#!/usr/bin/env bash
set -euo pipefail
TMPFILE=$(mktemp /tmp/demo.XXXXXX)
cleanup() {
rm -f "$TMPFILE"
echo "Temp file removed." >&2
}
on_interrupt() {
echo "" >&2
echo "Caught SIGINT — cancelling gracefully." >&2
exit 130 # EXIT trap (cleanup) runs automatically after this
}
trap cleanup EXIT
trap on_interrupt INT
echo "Running long task. Press Ctrl+C to cancel."
for i in $(seq 1 10); do
echo "Step $i/10..."
sleep 1
done
echo "All steps complete."Kombinera EXIT-, ERR- och INT-fällor
I produktionsskript registrerar ni vanligtvis alla tre fällorna tillsammans för att täcka alla sätt att avsluta:
- EXIT — körs alltid och hanterar filstädning.
- ERR — loggar kommandot som misslyckades och radnumret.
- INT — skriver ut ett meddelande om avbrytandet och avslutar med kod 130.
Eftersom EXIT alltid körs sist behöver städlogiken bara finnas på ett ställe. ERR- och INT-hanterare kan fokusera på loggning och tillståndsändringar och sedan överlåta själva städningen till EXIT genom att anropa exit.
Använd set -eEuo pipefail högst upp så att fel i funktioner också utlöser ERR och pipefail fångar fel inuti pipelines.
#!/usr/bin/env bash
set -eEuo pipefail
TMPFILE=$(mktemp /tmp/combined.XXXXXX)
ROLLBACK_NEEDED=false
cleanup() {
if [[ "$ROLLBACK_NEEDED" == true ]]; then
echo "Rolling back partial changes..." >&2
fi
rm -f "$TMPFILE"
echo "Cleanup done." >&2
}
on_error() {
ROLLBACK_NEEDED=true
echo "ERR at line $1: $BASH_COMMAND" >&2
}
on_interrupt() {
echo "Interrupted by user." >&2
exit 130
}
trap cleanup EXIT
trap 'on_error $LINENO' ERR
trap on_interrupt INT
echo "hello" > "$TMPFILE"
echo "Script finished successfully."Återställ och inaktivera fällor dynamiskt
Ibland behöver ni ändra en fälla mitt i skriptet — till exempel utföra en engångsstädning när ett kritiskt avsnitt är klart, så att efterföljande normala operationer inte utlöser onödig återställning.
trap - SIGNALåterställer signalen till dess inbyggda standardbeteende.trap '' SIGNALignorerar signalen helt (processen kan inte avslutas av den).- Ni kan registrera en ny hanterare när som helst; det senaste anropet av
trapgäller.
Ett vanligt mönster är att uppgradera EXIT-fällan när en riskfylld operation har lyckats och byta från en återställningshanterare till en enkel städfunktion.
#!/usr/bin/env bash
set -euo pipefail
TMPFILE=$(mktemp /tmp/staged.XXXXXX)
rollback() {
echo "ROLLBACK: removing $TMPFILE" >&2
rm -f "$TMPFILE"
}
cleanup_only() {
echo "CLEANUP: removing $TMPFILE" >&2
rm -f "$TMPFILE"
}
# Start with rollback in case something fails during the risky phase
trap rollback EXIT
echo "Performing risky operation..."
echo "critical data" > "$TMPFILE"
# ... imagine more risky steps here ...
# Risky phase succeeded — switch to simple cleanup
trap cleanup_only EXIT
echo "Risky phase done. Now doing safe finalization."
cp "$TMPFILE" /tmp/staged_result.txt
echo "All done."Vidarebefordra avslutskoder genom fällor
En subtil fallgrop är att skriptets slutliga avslutskod kan skrivas över om städfunktionen innehåller kommandon som kan misslyckas. Bevara den ursprungliga avslutskoden uttryckligen.
I en trap-hanterare innehåller $? avslutskoden som utlöste fällan. Spara den på hanterarens allra första rad, innan något annat kommando ändrar den.
#!/usr/bin/env bash
set -euo pipefail
TMPFILE=$(mktemp /tmp/exitcode.XXXXXX)
cleanup() {
local original_exit=$? # capture BEFORE any other command
echo "Cleaning up (original exit: $original_exit)" >&2
rm -f "$TMPFILE"
# Exit with the original code so callers see the real result
exit "$original_exit"
}
trap cleanup EXIT
echo "Doing work..."
echo "data" > "$TMPFILE"
# Simulate failure
if [[ ! -f /tmp/required_marker ]]; then
echo "Required marker missing!" >&2
exit 2
fi
echo "Done."Fällor i funktioner och subsheller
Det är avgörande att förstå hur fällor ärvs när ni skriver korrekta skript:
- Funktioner körs i samma shell och ärver fällor — men ERR förs bara vidare till funktioner när
set -E(errtrace) är aktivt. - Subsheller (
( ... )) startar med en kopia av förälderns fällor, men ändringar i subshellen påverkar inte föräldern. - Bakgrundsjobb (
cmd &) är subsheller och ärver inte förälderns INT-/TERM-fällor (de får signalernas standardhantering).
Praktisk regel: behåll registreringen av fällor i skriptets huvuddel, använd set -E när ERR behöver föras vidare till funktioner och förlita er aldrig på att fällor ärvs över &.
#!/usr/bin/env bash
set -eEuo pipefail # -E = errtrace: ERR propagates into functions
on_error() {
echo "ERR in function or main at line $1" >&2
}
trap 'on_error $LINENO' ERR
risky_function() {
echo "Inside risky_function"
ls /nonexistent_path # triggers ERR — works because of set -E
}
# Subshell: has its own copy; changes don't affect parent
(
trap '' ERR # disable ERR only inside subshell
ls /nonexistent_path 2>/dev/null || true
echo "Subshell completed without triggering parent ERR"
)
risky_functionPraktiskt mönster: atomiskt byte av filer
Ett klassiskt defensivt Bash-mönster är atomiskt byte av filer: skriv till en temporär fil och byt sedan namn på den så att den hamnar på rätt plats. Om något misslyckas före namnbytet förblir originalet orört. Fällor gör detta robust.
Steg:
- Skapa en temporär fil i samma filsystem som målfilen (så att
mvblir atomiskt). - Registrera en EXIT-fälla som tar bort den temporära filen om vi avslutar i förtid.
- Skriv och validera det nya innehållet.
- Byt namn atomiskt (
mv) — först nu ersätts originalet. - EXIT-fällan tar bara bort den temporära filen om den fortfarande finns (efter ett lyckat
mvär den borta).
#!/usr/bin/env bash
set -euo pipefail
DEST="/tmp/important_config.conf"
TMPFILE=$(mktemp "$(dirname "$DEST")/.tmp.XXXXXX")
cleanup() {
rm -f "$TMPFILE" # no-op if mv already moved it
}
trap cleanup EXIT
# Write new content to temp file
cat > "$TMPFILE" <<'EOF'
[settings]
version=2
mode=production
EOF
# Validate before replacing
if ! grep -q 'version=' "$TMPFILE"; then
echo "Validation failed — aborting replacement" >&2
exit 1
fi
# Atomic rename — DEST is replaced only here
mv "$TMPFILE" "$DEST"
echo "Config updated atomically: $DEST"Kunskapskontroll: ERR-fällans arv
Testa era kunskaper om hur ERR-fällan fungerar med funktioner i Bash.
Repetition: trap-hanterare för städning och signaler
I den här lektionen lärde ni er hur ni kan göra Bash-skript motståndskraftiga med hjälp av trap-hanterare:
- EXIT är ert universella skyddsnät — registrera den direkt efter att ni har skapat en temporär resurs och spara alltid
$?först för att bevara den ursprungliga avslutskoden. - ERR gör det möjligt att logga fel med
$LINENOoch$BASH_COMMAND; användset -Eså att funktioner ärver den. - INT hanterar Ctrl+C elegant — skriv ut ett meddelande och avsluta med kod 130 så att EXIT kan städa upp.
- Samla temporära resurser i en array och ta bort dem alla i en enda städfunktion.
- Använd
trap - SIGNALför att återställa ochtrap '' SIGNALför att ignorera signaler dynamiskt. - Det atomiska namnbytesmönstret (
mktemp→ skriv → validera →mv) i kombination med en EXIT-fälla garanterar att ofullständiga skrivningar aldrig förstör målfilen.
Genom att kombinera set -eEuo pipefail med välplacerade fällor får ni en stabil defensiv grund för alla Bash-skript i produktion.
Lär dig Bash med en AI-lärare – gratis
Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.
- Kurser
- 22
- Lektioner
- 88
Vanliga frågor
Är lektionen ”Trap-hanterare för städning och signaler” gratis?
Ja – hela texten till ”Trap-hanterare för städning och signaler” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i Bemästra Linux-kommandoraden och Bash-skriptning, kan Ni uppgradera till CoddyKit PRO. Kursen i Bemästra Linux-kommandoraden och Bash-skriptning innehåller totalt 4 lektioner.
Vad lär jag mig i ”Trap-hanterare för städning och signaler”?
Registrera EXIT-, ERR- och INT-traps för att pålitligt ta bort temporära filer och rulla tillbaka ofullständigt arbete. Ni övar på Bemästra Linux-kommandoraden och Bash-skriptning med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.
Behöver jag någon erfarenhet för att börja lära mig Bemästra Linux-kommandoraden och Bash-skriptning?
Du behöver inga förkunskaper. Utbildningen i Bemästra Linux-kommandoraden och Bash-skriptning på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 2 av 4.
Hur lång tid tar lektionen ”Trap-hanterare för städning och signaler”?
De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.
Kan jag skriva och köra kod i den här Bemästra Linux-kommandoraden och Bash-skriptning-lektionen?
Ja. Varje Bemästra Linux-kommandoraden och Bash-skriptning-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.
Alla lektioner i den här kursen
- Strikt läge med set -euo pipefail
- Trap-hanterare för städning och signaler
- Säkra temporära filer och låskataloger
- Idempotenta skript och logik för omförsök med backoff