trap în Linux / Bash

Scripting Bash POSIX / Bash built-in

Rulează comenzi când scriptul primește un semnal (INT, TERM) sau la ieșire (EXIT), de obicei pentru curățenie.

Sintaxă comandă
trap 'comenzi' SEMNAL [SEMNAL...]
trap - SEMNAL
trap -p [SEMNAL]

Ce face trap

trap înregistrează o acțiune care se execută automat când shell-ul primește un semnal, de exemplu INT (Ctrl+C) sau TERM (cererea de oprire trimisă de kill). Pseudo-semnalul EXIT se declanșează la orice ieșire din script, normală sau cu eroare.

Cea mai frecventă utilizare este curățenia: ștergerea fișierelor temporare, eliberarea unui fișier de blocare (lock) sau oprirea proceselor pornite în fundal, indiferent cum se termină scriptul.

Bash mai are pseudo-semnalele ERR (după o comandă care eșuează), DEBUG (înaintea fiecărei comenzi) și RETURN. SIGKILL (9) și SIGSTOP nu pot fi interceptate.

Opțiuni și argumente

Opțiune / Parametru Descriere
trap 'cmd' EXIT Rulează cmd când scriptul se termină, din orice motiv.
trap 'cmd' INT TERM Rulează cmd la Ctrl+C sau la kill PID.
trap '' INT Ignoră semnalul (șir gol): Ctrl+C nu mai oprește scriptul.
trap - INT Revine la comportamentul implicit al semnalului.
trap -p [SEMNAL] Afișează acțiunile înregistrate.
trap -l Listează numele și numerele semnalelor.

Exemple

Exemplul 1: Ștergerea fișierului temporar la ieșire

Funcția curata rulează la final, chiar dacă scriptul s-ar opri mai devreme din cauza unei erori.

curata() {
  rm -f "$TMP"
  echo "Fișierul temporar a fost șters"
}
TMP=$(mktemp ./lucru.XXXXXX)
trap curata EXIT
echo "Ana,9" > "$TMP"
echo "Lucrez cu un fișier temporar"

Rezultat

Lucrez cu un fișier temporar
Fișierul temporar a fost șters

Exemplul 2: Interceptarea semnalului TERM

Scriptul își trimite singur semnalul TERM. În loc să se oprească, rulează acțiunea din trap și continuă.

trap 'echo "Am primit SIGTERM, salvez starea"' TERM
trap -p TERM
kill -TERM $$
echo "Scriptul continuă"
trap - TERM

Rezultat

trap -- 'echo "Am primit SIGTERM, salvez starea"' SIGTERM
Am primit SIGTERM, salvez starea
Scriptul continuă

Exemplul 3: Oprire curată la Ctrl+C

Un script care rulează mult timp poate opri procesul din fundal și poate ieși cu codul 130 (convenția pentru Ctrl+C).

#!/usr/bin/env bash
opreste() {
  echo "Opresc procesarea..."
  kill "$PID_LUCRU" 2>/dev/null
  exit 130
}
trap opreste INT TERM

sleep 600 &
PID_LUCRU=$!
echo "Procesez datele (Ctrl+C pentru oprire)"
wait "$PID_LUCRU"

Ieșire în terminal

Procesez datele (Ctrl+C pentru oprire)
^COpresc procesarea...

Greșeli frecvente

  • Ghilimele duble în acțiune: trap "rm $TMP" EXIT înlocuiește $TMP în momentul în care rulează trap, nu la ieșire. Folosește ghilimele simple sau o funcție.
  • Așteptarea ca trap ... KILL să funcționeze: SIGKILL nu poate fi interceptat, deci curățenia nu rulează după kill -9.
  • Un al doilea trap ... EXIT înlocuiește primul, nu se adaugă la el. Pune toate acțiunile într-o singură funcție de curățenie.

Comenzi înrudite

  • kill: Trimite un semnal de control sau oprire către un proces specificat prin ID (PID).
  • exit: Încheie execuția shell-ului sau a scriptului curent și transmite un cod numeric de stare sistemului.
  • set -euo pipefail: Face un script Bash să se oprească la prima eroare, la variabile nedefinite și la comenzi eșuate din pipeline.
  • Funcții în Bash: Gruparea instrucțiunilor în blocuri reutilizabile de cod, cu variabile locale și parametri.