Capturing Advanced Signals in shell Scripts

Keywords: Linux shell

Signal capture in shell script

Traps, translated as trap s, are used to capture signals in shell scripts. What signal? For example, commonly used kill-9, kill-15, CTRL+C and so on are all signals.

1. View all available signals

Trap-l or kill-l

[root@linux1 ~]# kill -l
63) SIGRTMAX-1  64) SIGRTMAX    
[root@linux1 ~]# trap -l
 1) SIGHUP   2) SIGINT   3) SIGQUIT  4) SIGILL   5) SIGTRAP
 6) SIGABRT  7) SIGBUS   8) SIGFPE   9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
......  

2. Common signals are as follows:

Signal     Value     Comment
─────────────────────────────
SIGHUP        1      Termination of a process, especially when the terminal exits, will terminate the process within the terminal.
SIGINT        2      To interrupt a process is almost the same as to interrupt a process. sigterm,Release execution as much as possible clean-up,Release resources, save status, etc.(CTRL+C)
SIGQUIT       3      Kill from the keyboard(termination)Signaling of the process

SIGKILL       9      Force killing process, the signal can not be captured and ignored, the process will not execute any after receiving the signal clean-up Behavior, so resources will not be released, state will not be saved
SIGTERM      15      kill(termination)Process, almost equal to sigint Signals are released and executed as much as possible clean-up,Release resources, save status, etc.

SIGSTOP      19      The signal is a process stop message that can not be captured and ignored, and it will enter after receiving the signal. stopped state
SIGTSTP      20      This signal is a negligible process stop signal.(CTRL+Z)

The real signal name is not SIGXXX, but the word after removing SIG. Each signal has its corresponding code number.

For example, send a signal to a process whose PID is 12345

kill -1 12345
kill -HUB 12345
kill -SIGHUB 12345

3. trap options

Trap-l lists the signals supported by the current system, which have already been used. The root kill-l is the same.

Trap-p is equivalent to trap. Check the traps that the shell has laid out

You can see that the shell defaults to three traps, meaning that it ignores 20, 21, 22 signals.

[root@linux1 ~]# trap
trap -- '' SIGTSTP
trap -- '' SIGTTIN
trap -- '' SIGTTOU

4. What does a trap do when it catches a signal?

  • Ignore the signal
  • The signal is captured and processed accordingly. The main thing is to clean up some temporary files created by scripts and then exit.

5. Setting up a trap that can ignore CTRL+C and 15 signals

CTRL signal corresponds to SIGINT 15 signal and SIGTERM signal corresponds to SIGTERM signal.

[root@linux1 ~]# trap '' SIGINT SIGTERM
[root@linux1 ~]# trap
trap -- '' SIGINT
trap -- '' SIGTERM
trap -- '' SIGTSTP
trap -- '' SIGTTIN
trap -- '' SIGTTOU

In this way, the current shell cannot be killed by kill-15.

6. Set a trap and print "I caught you" when you catch the - 15 signal.

[root@linux1 ~]# Trap'echo''I caught you''TERM
[root@linux1 ~]# trap
trap -- '' SIGINT
trap -- 'echo "I caught you.~"' SIGTERM
trap -- '' SIGTSTP
trap -- '' SIGTTIN
trap -- '' SIGTTOU

As a result, when I initiated kill-15 signal on the current bash, it was printed out.

[root@linux1 ~]# echo $$
8827
[root@linux1 ~]# kill -15 8827
 I caught you.~
[root@linux1 ~]# kill -15 8827
 I caught you.~
[root@linux1 ~]# kill -15 8827
 I caught you.~

7. Set up a script in the script that can ignore CTRL+C and CTRL+Z signals

CTRL+C is 2 signal, SIGINT

CTRL+Z is 20 signal, SIGTSTP

Script:

The script sleeps for 10 seconds and then prints success, ignoring INT and TSTP signals.

[root@linux1 ~]# cat trap.sh
#!/bin/bash
trap '' SIGINT SIGTSTP
sleep 10
echo success

Effect:

<font color=red>CTRL+C can't stop me from sleeping either </font>

[root@linux1 ~]# bash trap.sh 
^C^C^Z^Z^C^C^Z^Zccc^Z^Z^Z^C^C^C

success

8. Layout a trap that clears garbage and exits the script immediately when the script is terminated

The script is as follows:

[root@linux1 ~]# cat trap1.sh
#!/bin/bash

trap 'echo trap handing...;rm -rf /tmp/$BASHPID;echo TEMP files cleaned;exit' SIGINT SIGTERM SIGQUIT SIGHUP
mkdir -p /tmp/$$/
touch /tmp/$$/{a..c}.txt
sleep 10
echo first sleep success
sleep 10
echo second sleep success

In this way, besides the SIGKILL signal (kill-9), scripts can always clean up temporary garbage.

Effect

At first it could not terminate, but later it was found that the previous shell itself set a trap to ignore CTRL+C, and it was enough to exit the shell and reenter.

[root@linux1 ~]# bash trap1.sh 
^Ctrap handing...
TEMP files cleaned

9. The guardian of the trap

The Guardian object of the trap is the shell process itself, not the child process in the shell environment. But if it's a signal-ignoring trap, the entire shell process group is guarded so that it ignores the given signal.

[root@linux1 ~]# cat trap2.sh 
#!/bin/bash
trap 'echo trap_handle_time: $(date +"%F %T")' SIGINT SIGTERM
echo time_start: $(date +"%F %T")
sleep 10
echo time_end1: $(date +"%F %T")
sleep 10
echo time_end2: $(date +"%F %T")

#After executing the script, the new terminal kills it with kill-15
[root@linux1 ~]# killall -s SIGTERM trap2.sh

#View the output
[root@linux1 ~]# ./trap2.sh 
time_start: 2019-08-27 10:43:48
trap_handle_time: 2019-08-27 10:43:58
time_end1: 2019-08-27 10:43:58
time_end2: 2019-08-27 10:44:08

It can be found that after kill ing is executed, the screen does not print trap_handle immediately, but only after sleep 10 is run. Sleep processes are guarded by neglected traps

Whenever a signal is sent to a shell process, it waits until the current running command has finished processing the signal, and then continues to run the script downward. (In fact, only when the operation being performed in the shell script is a signal-safe system call does the signal fail to interrupt the process, and we cannot directly know which system calls are being executed in the various commands under the shell.

However, the sleep() call initiated by the sleep command is signal-safe, so in the process of executing sleep in the script above, the signals do not interrupt their operation directly, but wait for it to run before executing the signal processing command.

10. If a trap is set in the shell for a signal, when the shell process receives the signal, <font color=red> waits for the end of the command running in the shell to start processing the trap </font>.

11. CTRL+C and SIGINT are not equivalent. When CTRL+C is pressed at a certain time, it sends SIGINT signals to the entire current running process group. For shell scripts, SIGINT is sent not only to the shell script process, but also to the currently running process in the script.

[root@linux1 ~]# cat trap2.sh 
#!/bin/bash
trap 'echo trap_handle_time: $(date +"%F %T")' SIGINT SIGTERM
echo time_start: $(date +"%F %T")
sleep 10
echo time_end1: $(date +"%F %T")
sleep 10
echo time_end2: $(date +"%F %T")

#After executing the script, immediately CTRL+C
[root@linux1 ~]# bash trap2.sh 
time_start: 2019-08-27 10:20:53
^Ctrap_handle_time: 2019-08-27 10:20:54
time_end1: 2019-08-27 10:20:54
time_end2: 2019-08-27 10:21:04

It can be found that after CTRL+C, not only trap is processed, but sleep is also terminated immediately. This shows that CTRL+C not only makes the script process receive SIGINT signal, but also makes the current process receive SIGINT signal.

It's a little hard to understand. Come back later.

Posted by ded on Mon, 26 Aug 2019 20:11:07 -0700