活学活用掌握trap命令


trap 命令用于指定在接收到信号后将要采取的动作,常见的用途是在脚本程序被中断时完成清理工作。当 shell 接收到 sigspec 指定的信号时, arg 参数(通常是执行命令)会被读取,并被执行。

活学活用掌握trap命令


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] 捕获SIGINTCtrl+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

文章作者: Escape
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Escape !
  目录