[root@linuxidc ~]# vim trap8.sh #!/bin/bash set -e trap 'echo continue' ERR echo "right here" mv ~/a.txt [ "$?" -eq 0 ] && echo "right again" || echo "wrong here" echo haha
执行结果如下:
[root@linuxidc ~]# ./trap8.sh right here mv: missing destination file operand after ‘/root/a.txt’ Try 'mv --help' for more information. continue
(8).在trap中两个很好用的变量:BASH_COMMAND和LINENO。BASH_COMMAND变量记录的是当前正在执行的命令行,如果是用在陷阱中,则记录的是陷阱触发时正在运行的命令行。LINENO记录的是正在执行的命令所处行号。
例如:
[root@linuxidc ~]# vim trap8.sh #!/bin/bash set -e trap 'echo "error line: $LINENO,error cmd: $BASH_COMMAND"' ERR echo "right here" mv ~/a.txt
执行结果。
[root@linuxidc ~]# ./trap8.sh right here mv: missing destination file operand after ‘/root/a.txt’ Try 'mv --help' for more information. error line: 5,error cmd: mv ~/a.txt
(9).处理脚本中启动的后台进程。
通常trap在脚本中的作用之一是在突然被中断时清理一些临时文件然后退出,虽然它会等待脚本中当前正在运行的命令结束,然后清理并退出。但是,很多时候会在脚本中使用后台进程,以加快脚本的速度。而后台进程是独立挂靠在init/systemd下的,所以它不受终端以及shell环境的影响。换句话说,当脚本突然被中断时,即使陷阱捕获到了该信号,并清理了临时文件后退出,但是那些脚本中启动的后台进程还会继续运行。
这就给脚本带来了一些不可预测性,一个健壮的脚本必须能够正确处理这种情况。trap可以实现比较好的解决这种问题,方法是在trap的命令行中加上向后台进程发送信号的语句,然后再退出。
以下面的脚本为例。
[root@linuxidc ~]# vim trap10.sh #!/bin/bash trap 'echo first trap $(date +"%F %T");exit' SIGTERM echo first sleep $(date +"%F %T") sleep 20 & echo second sleep $(date +"%F %T") sleep 5
该脚本中首先将一个sleep放入后台运行。正常情况下,该脚本执行5秒后就会退出,但在20秒后后台进程sleep才会结束,即使突然发送中断信号TERM触发trap也一样。
于是现在的目标是,在sleep 5的过程中突然中断脚本时,能杀死后台sleep进程。可以使用"!"这个特殊变量。修改后的脚本如下。
[root@linuxidc ~]# vim trap10.sh #!/bin/bash trap 'echo first trap $(date +"%F %T");kill $pid;exit' SIGTERM echo first sleep $(date +"%F %T") sleep 20 & pid="$!" sleep 30 & pid="$! $pid" echo second sleep $(date +"%F %T") sleep 5
执行该脚本,并在另一个会话窗口发送SIGTERM信号给该脚本进程。
[root@linuxidc ~]# ./trap10.sh ; ps aux | grep sleep [root@linuxidc ~]# kill trap10.sh # 另一个会话窗口执行
执行结果如下。可见sleep被正常终止。