Trap-behandlere for opprydding og signaler
Registrer EXIT-, ERR- og INT-trap-er for å fjerne midlertidige filer og pålitelig rulle tilbake delvis arbeid.
Trap-behandlere for opprydding og signaler er en gratis leksjon i DevOps-bootcamp på CoddyKit. Dette er leksjon 2 av 4. Du kan lese valgfritt 3 leksjoner fra denne læringsstien gratis i sin helhet – deretter låser CoddyKit PRO opp alle leksjoner, samt praktisk øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i DevOps-bootcamp, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i DevOps-bootcamp inneholder totalt 4 leksjoner.
Hvorfor trap-behandlere er viktige
Når et Bash-skript avsluttes — enten normalt, på grunn av en feil eller fordi brukeren trykket Ctrl+C — kan det etterlate midlertidige filer, delvis skrevne data eller en ødelagt tilstand. Uten opprydding hoper disse restene seg opp og forårsaker problemer som er vanskelige å feilsøke.
Trap-behandlere løser dette ved å registrere en funksjon eller kommando som Bash kjører automatisk når et bestemt signal eller pseudosignal mottas.
- EXIT — utløses hver gang skriptet avsluttes, uansett årsak
- ERR — utløses etter at en kommando returnerer en avslutningsstatus ulik null
- INT — utløses når brukeren sender SIGINT (Ctrl+C)
- TERM — utløses ved SIGTERM (for eksempel fra
kill)
Et godt skrevet skript registrerer disse trap-behandlerne helt øverst, før risikofylt arbeid begynner.
Syntaks for den innebygde trap-kommandoen
Den innebygde kommandoen trap registrerer en behandler for ett eller flere signaler eller pseudosignaler. Den generelle syntaksen er:
trap 'command_or_function' SIGNAL [SIGNAL...]
Viktige regler:
- Det første argumentet er en streng med shell-kode i anførselstegn (eller et funksjonsnavn) som skal kjøres når signalet utløses.
- De kan liste flere signaler etter behandleren.
trap '' SIGNALignorerer signalet (tom behandler).trap - SIGNALtilbakestiller signalet til standardatferden.
Trap-behandlere arves av funksjoner som kalles i samme shell, men ikke av subshells som startes 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-trap-behandleren — sikkerhetsnettet Deres
Pseudosignalet EXIT er den viktigste trap-behandleren å registrere. Den utløses når skallet avsluttes av enhver grunn: normal fullføring, exit N, en uhåndtert feil eller et signal. Dette gjør den ideell for å fjerne midlertidige filer.
Anbefalt praksis:
- Opprett midlertidige filer med
mktempslik at navnet er unikt og uforutsigbart. - Lagre banen i en variabel umiddelbart.
- Registrer EXIT-trap-behandleren rett etter opprettelsen, slik at oppryddingen alltid kjøres.
Skriptets avslutningskode bevares — avslutningskoden til trap-behandleren ignoreres med mindre De eksplisitt kaller 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."Håndtering av flere midlertidige filer og kataloger
Reelle skript oppretter ofte flere midlertidige ressurser — filer, kataloger, FIFO-er og låsefiler. I stedet for å holde oversikt over hver enkelt separat kan De samle dem i en tabell og fjerne alt i én oppryddingsfunksjon.
Dette mønsteret skalerer ryddig: Hver gang De oppretter en ny midlertidig ressurs, legger De den til i tabellen. EXIT-trap-behandleren håndterer alltid hele listen, uansett hvor skriptet avsluttes.
#!/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-trap-behandleren — fange opp feil
Pseudosignalet ERR utløses etter at en enkel kommando returnerer en avslutningsstatus ulik null, forutsatt at shell-alternativet set -e (errexit) er aktivt eller at kommandoen ikke befinner seg i en sammensatt if-, while- eller ||/&&-konstruksjon.
Bruk ERR-trap-behandleren til å:
- Logge hvilken linje som mislyktes, ved hjelp av
$LINENOog$BASH_COMMAND. - Utløse tilbakerullingslogikk før EXIT-trap-behandleren kjøres.
- Skrive strukturerte feilmeldinger til stderr.
Viktig: ERR-trap-behandlere utløses ikke inne i funksjoner med mindre De eksplisitt kjører set -E (errtrace), slik at funksjoner arver ERR-trap-behandleren fra skallet som kalte dem.
#!/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-trap-behandleren — kontrollert Ctrl+C
Hvis De trykker Ctrl+C, sendes SIGINT til prosessgruppen i forgrunnen. Uten en trap-behandler avslutter Bash umiddelbart, og kan dermed etterlate delvis utført arbeid.
Ved å registrere en INT-trap-behandler kan De:
- Skrive ut en brukervennlig melding om avbrytelsen.
- Utføre eventuell mellomliggende tilbakerulling før kontrollen overlates til EXIT-trap-behandleren.
- Avslutte med en meningsfull statuskode (
130er standardkoden for SIGINT:128 + 2).
Når INT-behandleren er ferdig, kaller De exit 130 for å videreføre riktig avslutningskode. EXIT-trap-behandleren kjøres deretter automatisk.
#!/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."Kombinere EXIT-, ERR- og INT-trap-behandlere
I produksjonsskript registrerer De vanligvis alle tre trap-behandlerne sammen for å dekke alle avslutningsveier:
- EXIT — kjøres alltid og håndterer filopprydding.
- ERR — logger kommandoen som mislyktes og linjenummeret.
- INT — skriver ut en melding om avbrytelsen og avslutter med kode 130.
Fordi EXIT alltid kjøres sist, trenger oppryddingslogikken bare å finnes på ett sted. ERR- og INT-behandlerne kan konsentrere seg om logging og tilstandssetting, og deretter overlate selve oppryddingen til EXIT ved å kalle exit.
Bruk set -eEuo pipefail øverst, slik at feil i funksjoner også utløser ERR, og pipefail fanger opp feil inne i 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."Tilbakestille og deaktivere trap-behandlere dynamisk
Noen ganger må De endre en trap-behandler midt i skriptet — for eksempel utføre en engangsopprydding etter at en kritisk seksjon er fullført, slik at påfølgende normale operasjoner ikke utløser unødvendig tilbakerulling.
trap - SIGNALtilbakestiller signalet til den innebygde standardatferden.trap '' SIGNALignorerer signalet fullstendig (prosessen kan ikke avsluttes med det).- De kan registrere en ny behandler når som helst; det siste
trap-kallet gjelder.
Et vanlig mønster er å oppgradere EXIT-trap-behandleren når en risikofylt operasjon lykkes, ved å bytte fra en tilbakerullingsbehandler til en enkel oppryddingsbehandler.
#!/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."Videreføre avslutningskoder gjennom trap-behandlere
En subtil fallgruve er at skriptets endelige avslutningskode kan bli overskrevet hvis oppryddingsfunksjonen inneholder kommandoer som kan mislykkes. Bevar den opprinnelige avslutningskoden eksplisitt.
Inne i en trap-behandler inneholder $? avslutningskoden som utløste trap-behandleren. Lagre den på den aller første linjen i behandleren, før andre kommandoer endrer 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."Trap-behandlere i funksjoner og subshells
Det er avgjørende å forstå trap-arv for å skrive korrekte skript:
- Funksjoner kjører i samme shell og arver trap-behandlere — men ERR videreføres til funksjoner bare når
set -E(errtrace) er aktivt. - Subshells (
( ... )) starter med en kopi av forelderens trap-behandlere, men endringer inne i subshellen påvirker ikke forelderen. - Bakgrunnsjobber (
cmd &) er subshells og arver ikke forelderens INT-/TERM-trap-behandlere (de får standard signalhåndtering).
Praktisk regel: Hold registreringen av trap-behandlere i hoveddelen av skriptet, bruk set -E når De trenger at ERR videreføres til funksjoner, og stol aldri på at trap-behandlere arves på tvers av &.
#!/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_functionPraktisk mønster: atomisk erstatning av filer
Et klassisk defensivt Bash-mønster er atomisk filutskifting: skriv til en midlertidig fil, og gi den deretter det endelige navnet. Hvis noe mislykkes før navneendringen, forblir originalen urørt. Trap-behandlere gjør dette robust.
Trinn:
- Opprett en midlertidig fil på samme filsystem som målet (slik at
mvblir atomisk). - Registrer en EXIT-trap-behandler som fjerner den midlertidige filen hvis vi avslutter tidlig.
- Skriv og valider det nye innholdet.
- Gi filen atomisk nytt navn (
mv) — først nå erstattes originalen. - EXIT-trap-behandleren fjerner den midlertidige filen bare hvis den fortsatt finnes (etter en vellykket
mver den borte).
#!/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"Kunnskapssjekk: ERR-trap-arv
Test forståelsen Deres av hvordan ERR-trap-behandleren oppfører seg med funksjoner i Bash.
Oppsummering: Trap-behandlere for opprydding og signaler
I denne leksjonen lærte De hvordan Bash-skript kan bli robuste ved hjelp av trap-behandlere:
- EXIT er det universelle sikkerhetsnettet — registrer den umiddelbart etter at en midlertidig ressurs er opprettet, og lagre alltid
$?først for å bevare den opprinnelige avslutningskoden. - ERR lar Dem logge feil med
$LINENOog$BASH_COMMAND; brukset -Eslik at funksjoner arver den. - INT håndterer Ctrl+C kontrollert — skriv ut en melding og avslutt med kode 130, slik at EXIT kan utføre oppryddingen.
- Samle midlertidige ressurser i en tabell og fjern dem alle i én oppryddingsfunksjon.
- Bruk
trap - SIGNALfor å tilbakestille ogtrap '' SIGNALfor å ignorere signaler dynamisk. - Det atomiske navneendringsmønsteret (
mktemp→ skriv → valider →mv) kombinert med en EXIT-trap-behandler garanterer at delvise skrivinger aldri ødelegger målfilen.
Ved å kombinere set -eEuo pipefail med trap-behandlere på riktige steder får De et solid defensivt grunnlag for alle Bash-skript i produksjon.
Lær deg DevOps-bootcamp med en AI-veileder – gratis
Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.
- Kurs
- 142
- Leksjoner
- 568
Ofte stilte spørsmål
Er leksjonen «Trap-behandlere for opprydding og signaler» gratis?
Ja – du kan lese valgfritt 3 av leksjonene i læringsstien DevOps-bootcamp, inkludert «Trap-behandlere for opprydding og signaler», gratis i sin helhet her på nettet. Deretter låser CoddyKit PRO opp alle leksjoner, samt interaktiv øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Kurset i DevOps-bootcamp inneholder totalt 4 leksjoner.
Hva lærer jeg i «Trap-behandlere for opprydding og signaler»?
Registrer EXIT-, ERR- og INT-trap-er for å fjerne midlertidige filer og pålitelig rulle tilbake delvis arbeid. Du øver på DevOps-bootcamp med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.
Trenger jeg erfaring for å begynne med DevOps-bootcamp?
Ingen tidligere erfaring er nødvendig. DevOps-bootcamp på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 2 av 4.
Hvor lang tid tar leksjonen «Trap-behandlere for opprydding og signaler»?
De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.
Kan jeg skrive og kjøre kode i denne DevOps-bootcamp-leksjonen?
Ja. Alle DevOps-bootcamp-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.
Alle leksjonene i dette kurset
- Streng modus med set -euo pipefail
- Trap-behandlere for opprydding og signaler
- Sikre midlertidige filer og låsekataloger
- Idempotente skript og retry-logikk med backoff