Use trap to set traps for shell signals, how traps work, and how to restore default signal processing

Posted by digi24 on Thu, 20 Jan 2022 16:24:40 +0100

Trap signal

When your program is running, press Control-C or control -, and the program will terminate as soon as the signal arrives. But in many cases, you may not want the program to stop immediately when the signal arrives. Instead, it can hope to ignore this signal and run all the time, or do some cleanup before the program exits. The trap command allows you to control the behavior of your program after receiving the signal.
The definition of a signal is an asynchronous message composed of numbers sent by one process to another, or sent by the operating system to the process after a specific key is pressed, or when an exception occurs. The trap command tells the shell to terminate the current process in different ways according to the received signal. If the trap command is followed by a command quoted in quotation marks, the command is executed after the specified number is received. The shell reads the command string twice, once when trap is set and once when the signal reaches. If the command string is referenced in double quotation marks, variable and command substitution is performed at the first trap setting. If it is quoted in single quotation marks, variables and command replacement will not be run until the signal reaches the trap to start execution.

format
trap 'command; command' signal-num
trap 'command; command' signal-name

Example 1

trap  'rm file; exit 1' 0 1 2 15
trap  'rm file; exit 1' EXIT HUP INT TERM
# Both ways are the same

If the system receives a prefix SIG during the running of a script, such as SIGHUP, SIGINT, etc. bash allows you to use symbolic names on signals. For example, there is no prefix or a number is used as the name of the signal. A pseudo signal called EXIT or the number 0 will trigger the execution of a trap when the shell exits.
See the document for detailed signal description. Common signals and their numerical codes and descriptions are as follows:
Signal Value Comment

SIGHUP 1 terminates the process, especially when the terminal exits, the processes in the terminal will be terminated
SIGINT 2 interrupts the process, which is almost equivalent to sigterm. It will release and execute clean-up, release resources, save status, etc. as much as possible (CTRL+C)
SIGQUIT 3 sends a signal from the keyboard to kill (terminate) the process

SIGKILL 9 forcibly kills the process. This signal cannot be captured or ignored. After receiving this signal, the process will not perform any clean-up behavior, so the resources will not be released and the state will not be saved
SIGTERM 15 kills (terminates) the process, which is almost equivalent to a sign signal. It will release and execute clean-up, release resources, save state, etc. as much as possible

SIGSTOP 19 this signal is a process stop message that cannot be captured and ignored. After receiving the signal, it will enter the stopped state
SIGTSTP 20 this signal is a negligible process stop signal (CTRL+Z)

Signal reset: the trap command is followed by a signal or number, which can reset the signal to the default action. Once the function is called, the trap set by the function can be recognized by the shell calling the function. At the same time, traps set outside the function can also be recognized by the function.

Example 1

trap 2 or trap INT #Set the default action for signal 2. This signal is triggered when Ctrl-C is pressed
# This usage is not recommended and may have side effects.
trap - signal-list # This method has the same effect as the above method and is more stable.

Ignore signals: if the trap command is followed by a pair of empty quotes, the signals in the list will be ignored by the process.

trap " " 1 2
trap " " HUP INT
#Signals 1 and 2 will be ignored by the shell

**Trap list: * * you can display the list of traps and the list of commands assigned to traps by entering the trap command.

The syntax format of trap is:

1.trap [-lp]
2.trap cmd-body signal_list
3.trap '' signal_list
4.trap signal_list
5.trap - signale_list

Syntax description:
Syntax 1: the - l option is used to list the signals supported by the current system. It has the same function as "kill -l".
-The p option is used to list the traps that have been arranged in the current shell environment.
Syntax 2: when a signal in the given signal list is captured, execute the command in CMD body given here.
Syntax 3: when the command parameter is an empty string, both the shell process and the child process in the shell process will ignore the signal in the signal list.
Syntax 4: omit the command parameters and reset the trap to the trap when starting the shell. This syntax is not recommended, and the results will be unexpected when multiple signals are given.
Syntax 5: equivalent to syntax 4.
When trap does not receive any parameters and options, it defaults to "- p".

$ trap 'echo hello world' 2
$ trap # Show traps with default settings
# trap -- 'shell_session_update' EXIT
# trap -- 'echo hello world ' SIGKILL
# trap -- ' ' SIGINT

Example 1

#!/usr/bin/bash
# scriptname: trapping.sh
trap 'echo "Control-C will not terminate $0."' INT
trap 'echo "Control-\ will not terminate $0."' QUIT
trap 'echo "Control-Z will not terminate $0."' TSTP

echo "When you are ready to exit, please enter a \"stop.\""
while true
do
  echo "go ahead --->"
  read
  if [[ $REPLY == [sS]top ]] # If no variable is specified for the read command, the input content is saved in REPLY by default
  then
      break
  fi
done  
(The output)
$ bash trapping.sh 
#When you are ready to exit, please enter a "stop."
#go ahead --->
#w
#go ahead --->
#e
#go ahead --->
#^ZControl-Z will not terminate trapping.sh.
#^CControl-C will not terminate trapping.sh.
#^\Control-\ will not terminate trapping.sh.
#^CControl-C will not terminate trapping.sh.
#^CControl-C will not terminate trapping.sh.
#^CControl-C will not terminate trapping.sh.
#^CControl-C will not terminate trapping.sh.
#^CControl-C will not terminate trapping.sh.
#^CControl-C will not terminate trapping.sh.
#^CControl-C will not terminate trapping.sh.
#^CControl-C will not terminate trapping.sh.
#stop #The first three signals trigger the set command and print out the content, but do not terminate the script until you enter stop to terminate the loop.

**Reset signal: * * after the trap command, take the signal name or number as the parameter, and the reset signal can be the default action. Of course, the default behavior of the signal can also be reset in the form of trap - siglist.

trap 'trap - 2' 2
# You need to press twice to terminate the process

**Traps in functions: * * if traps are used to handle signals in functions, once the function is activated, it will affect the whole script. Traps are global to scripts. In the following example, the trap is set to ignore the interrupt ctrl-c. To terminate the loop of this script, you can only use the kill command. It proves that using traps in functions can be unpredictable.

#!/usr/bin/bash
function trapper {
   echo "In trapper"
   trap 'echo "Caught in a trap"' INT
}

while : #Equivalent to true
do
  echo "In the main script"
  trapper
  echo "still in main"
  sleep 5
done  

(The output)
Output after executing the above script:

#In the main script
#In trapper
#still in main
#^CCaught in a trap
#In the main script
#In trapper
#still in main
#^CCaught in a trap
#In the main script
#In trapper
#still in main