GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Identifizieren des empfangenen Signalnamens in Bash

(Wenn Sie nur die Nummer eines Signals haben und den Namen wollen, kill -l $SIGNAL_NUM druckt den Namen eines Signals; Sie können dies vermeiden, indem Sie die Signalnamen anstelle von Nummern in Ihrem Aufruf an trap verwenden wie unten.)

Diese Antwort besagt, dass es keine Möglichkeit gibt, auf den Signalnamen zuzugreifen, aber wenn Sie für jedes Signal, das Sie abfangen, eine separate Funktion haben, kennen Sie den Signalnamen bereits:

trap 'echo trapped the HUP signal' HUP
trap 'echo different trap for the INT signal' INT

In vielen Fällen mag das ausreichen, aber eine andere Antwort auf dieselbe Frage nutzt diese Tatsache, um eine Problemumgehung bereitzustellen, um das gewünschte Verhalten vorzutäuschen. Es nimmt eine Funktion und eine Liste von Signalen und setzt eine separate Falle für jedes Signal auf dieser Funktion, die mit dem Signalnamen aufgerufen wird, also ist es intern eigentlich eine separate Funktion für jedes Signal, aber es sieht aus wie eine einzelne Falle für eine einzelne Funktion, die die erhält Signalname als Argument:

Code:

#!/bin/bash

trap_with_arg() {
    func="$1" ; shift
    for sig ; do
        trap "$func $sig" "$sig"
    done
}

func_trap() {
    echo "Trapped: $1"
}

trap_with_arg func_trap INT TERM EXIT

echo "Send signals to PID $$ and type [enter] when done."
read # Wait so the script doesn't exit.

Wenn ich das ausführe, kann ich Signale an den Prozess senden und bekomme eine Ausgabe wie

Trapped: INT
Trapped: TERM
Trapped: EXIT

Bezugnehmend auf $? obige Lösung:$? gibt den Exit-Code des zuletzt ausgeführten Befehls wieder. Bedenken Sie Folgendes:

#!/bin/bash
trap 'echo CODE: $?; exit 1' 1 2 3 15
sleep 3600

Wenn Sie dies ausführen und Strg-C drücken , es wird CODE: 130 ausgegeben . Das liegt daran, dass sleep ausführbare Datei wurde durch SIGINT unterbrochen und mit diesem Code beendet.

Vergleichen Sie das mit:

#!/bin/bash
trap 'echo CODE: $?; exit 1' 1 2 3 15
read X

Wenn Sie dies ausführen und Strg-C drücken , es wird CODE: 0 ausgegeben , vermutlich weil die read Der Befehl ist ein eingebauter Befehl und die Exit-Code-Regeln sind unterschiedlich (dasselbe passiert, wenn Sie while : ; do : ; done unterbrechen würden ).

Also $? informiert Sie nur über das Signal, wenn es einen externen Befehl unterbrochen hat, und wenn dieses bestimmte Programm das Signal nicht abgefangen und mit seinem eigenen Exit-Code beendet hat. Point-in-Case ist das obige Bash-Skript:Beim Empfang eines SIGINT wird es mit dem Code 1 beendet , nicht 130 .


Innerhalb der Falle (wenn sie über ein Signal ausgelöst wird) wird das $? Die Variable ist anfänglich auf die Signalnummer plus 128 gesetzt, sodass Sie die Signalnummer einer Variablen zuweisen können, indem Sie die erste Anweisung der Trap-Aktion auf etwas wie

setzen
sig=$(($? - 128))

Sie können dann den Namen des Signals mit dem Kill-Befehl abrufen

kill -l $sig

Update:Wie in den Kommentaren erwähnt, funktioniert dies für einige eingebaute Shell-Befehle nicht. Damit diese das $ der Falle stellen? Variable, sie können in einer Subshell ausgeführt werden, zB

(read)

statt

read

ein einfacher Weg, dies zu tun:

_handler() {
   signal=$1
   echo signal was $signal
 }

 trap '_handler SIGTERM' SIGTERM
 trap '_handler SIGINT'  SIGINT

Linux
  1. Woher weiß ich den Namen der Skriptdatei in einem Bash-Skript?

  2. Python - Trap alle Signale

  3. Wie konvertiert man .. in Pfadnamen in absolute Namen in einem Bash-Skript?

  4. BASH:SIGTSTP-Signal senden (Strg+Z)

  5. Wie entferne ich nachgestellte Zeichen in Dateinamen in Bash?

Bash-Wartebefehl

Bash-while-Schleife

Bash-Funktionen

Bash Shebang

Nützliche Bash-Befehle, die Sie vielleicht nicht kennen

Linux Bash Scripting Part5 – Signale und Jobs