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.