为shell布置陷阱:trap捕捉信号方法论(5)

[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被正常终止。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/13539.html