活学活用掌握trap命令
trap 命令用于指定在接收到信号后将要采取的动作,常见的用途是在脚本程序被中断时完成清理工作。当 shell 接收到 sigspec 指定的信号时, arg 参数(通常是执行命令)会被读取,并被执行。
1. 命令介绍
开始掌握基本的使用方式和方法
[1] 语法格式
- trap [-lp] [[arg] sigspec ...]
[2] 参数选项
编号 | 参数 | 含义 |
---|---|---|
1 | -p | 列出当前设置的 trap 方法 |
2 | -l | 列出信号名称和相应的数字 |
[3] 常用的信号量
Number | Name | Notes |
---|---|---|
0 | EXIT | Always run on shell exit, regardless of exit code |
1 | SIGHUP | - |
2 | SIGINT | This is what ^C sends |
3 | SIGQUIT | - |
6 | SIGABRT | - |
9 | SIGKILL | - |
14 | SIGALRM | - |
15 | SIGTERM | This is what kill sends by default |
2. 实例说明
纸上得来终觉浅,绝知此事要躬行。
- [1] 累计在退出时运行的trap工作列表
# on_exit and add_on_exit # Usage: # add_on_exit rm -f /tmp/foo # add_on_exit echo "I am exiting" # tempfile=$(mktemp) # add_on_exit rm -f "$tempfile" function on_exit() { for i in "${on_exit_items[@]}"; do eval $i done } function add_on_exit() { local n=${#on_exit_items[*]} on_exit_items[$n]="$*" if [[ $n -eq 0 ]]; then trap on_exit EXIT fi } add_on_exit echo "I am exiting"
- [2] 捕获SIGINT或Ctrl+C
# Run a command on signal 2 (SIGINT, which is what ^C sends) function sigint() { echo "Killed subshell!" } trap sigint INT # This will be killed on the first ^C echo "Sleeping..." sleep 500 echo "Sleeping..." sleep 500
# pressing ^C twice in a second to quit last=0 function allow_quit() { [ $(date +%s) -lt $(( $last + 1 )) ] && exit echo "Press ^C twice in a row to quit" last=$(date +%s) } trap allow_quit INT
- [3] 清理临时文件
# Make a cleanup function function cleanup() { rm --force -- "${tmp}" } # Trap special "EXIT" group, which is always run when the shell exits. trap cleanup EXIT # Create a temporary file tmp="$(mktemp -p /tmp tmpfileXXXXXXX)" echo "Hello, world!" >> "${tmp}"
- [4] 在退出时杀死子进程
# kill all spawned child processes of the shell on exit trap 'jobs -p | xargs kill' EXIT
- [5] 对终端窗口大小的变化做出反应
# signal WINCH(WINdowCHange) that is fired when one resizes a terminal window declare -x rows cols function update_size(){ rows=$(tput lines) # get actual lines of term cols=$(tput cols) # get actual columns of term echo DEBUG terminal window has no $rows lines and is $cols characters wide } trap update_size WINCH
3. 删除进程树
一条命令也可以完成一个脚本的工作量
# How to get PID,PGID,sessionid etc ? $ ps -o pid,ppid,pgid,gid,sess,cmd -U root PID PPID PGID GID SESS CMD
# 1.kill a group of processes with negative PID(Process ID) $ kill -TERM -PID # 2. kill a group of processes with their PGID(Process Group ID) $ kill -- -$PGID Kill using the default signal (TERM = 15) $ kill -9 -$PGID Kill using the KILL signal (9) # 3. kill a group processes with only PID info $ kill -- -$(ps -o pgid= $PID | grep -o [0-9]*) # 4.Using pkill, kill processes by PGID(Proess Group ID) $ pkill -9 -g $PGID # 5.Using pkill, kill processes by GID(Group ID) $ pkill -9 -G $GID # 6.Using pkill, kill processes by PPID(Parent Process ID) $ pkill -9 -p $PPID # 7.Using pkill, kill processes by terminal $ pkill -9 -t $terminal # 8.Using pkill, kill processes by process name $ pkill -9 -x $process_name # 9.Using pkill, kill processes by session $ pkill -9 -s $sess