Exit-Trap in Dash vs. KSH und Bash

Exit-Trap in Dash vs. KSH und Bash

Hier ist ein einfaches Skript, das ein temporäres Verzeichnis im aktuellen Verzeichnis und eine Trap-Funktion zum Löschen dieses Verzeichnisses beim Beenden einrichtet.

#filename: script   
set -x  
trap 'rm -rf "$d"' exit
d=`TMPDIR=$PWD mktemp -d`
"$@"

Wenn ich ksh script sleep 100oder mache bash script sleep 100und es mit unterbreche, C-Cwird der Trap ausgeführt und das Verzeichnis gelöscht. Mit funktioniert es nicht dash. Warum? Ist das ein Fehler oder beabsichtigtes Verhalten?

Antwort1

zsh, pdksh(allerdings nicht neuere Versionen von , die mkshdavon abgeleitet sind), yash, die Bourne-Shell verhält sich wie dash.

Nur bash, ksh88, ksh93und mkshverhalten sich anders.

SIGINTAus der POSIX-Spezifikation geht nicht eindeutig hervor, welches Verhalten korrekt sein sollte, aber es gibt dort keinen Hinweis darauf, dass die Shell den Standardhandler für das (oder ein anderes) Signal überschreiben darf .

Dort heißt es, EXITdass die Trap-Aktion ausgewertet werden soll, wenn exitsie aufgerufen wird. Soweit ich weiß, wird dort jedoch nicht einmal angegeben, ob sie beispielsweise ausgewertet werden soll, wenn die Shell aufgrund von set -eFehlerbedingungen set -uwie Syntaxfehlern oder fehlgeschlagenen speziellen integrierten Funktionen beendet wird.

Um beim Empfang eines Signals eine Trap ausführen zu können EXIT, müsste die Shell einen Handler für dieses Signal installieren.

Das ist ksh, was mkshund bashtun, aber die Liste der Signale, die sie verarbeiten, ist bei allen drei Implementierungen unterschiedlich. Die einzigen gemeinsamen Signale bei allen drei scheinen INT, QUIT, TERM, ALRMund zu sein HUP.

Wenn Sie möchten, dass die EXITTrap bei bestimmten Signalen ausgeführt wird, besteht die portable Möglichkeit darin, diese Signale selbst zu verarbeiten:

trap 'exit 1' INT HUP QUIT TERM ALRM USR1
trap 'cleanup' EXIT

Dieser Ansatz funktioniert jedoch nicht mit , da dieses Trap zshnicht ausführt , wenn es von einem Trap-Handler aufgerufen wird.EXITexit

Außerdem wird Ihr Tod Ihren Eltern nicht per Signal gemeldet.

Sie könnten stattdessen Folgendes tun:

for sig in INT QUIT HUP TERM ALRM USR1; do
  trap "
    cleanup
    trap - $sig EXIT
    kill -s $sig "'"$$"' "$sig"
done
trap cleanup EXIT

Beachten Sie jedoch, dass während der Ausführung weitere Signale eintreffen cleanupund cleanupmöglicherweise erneut ausgeführt werden. Sie sollten sicherstellen, dass Ihr cleanupProgramm auch bei mehrmaligem Aufruf korrekt funktioniert und/oder Signale während der Ausführung ignoriert.

Antwort2

Achtung: exitEs gibt keine Garantie, dass es funktioniert. Sie sollten stattdessen verwendenEXIT

Da der POSIX-Standard nicht definiert, ob der EXITTrap auch im Falle eines Signals ausgeführt werden soll, und da die Bourne Shell den EXITTrap in dem von Ihnen genannten Fall nicht aufruft, ist es offensichtlich, dass Sienicht spezifiziertVerhalten.

verwandte Informationen