[转帖]Bash脚本编程学习笔记11:信号捕捉

bash,脚本,编程,学习,笔记,信号,捕捉 · 浏览次数 : 0

小编点评

## 脚本解析和陷阱设置 这篇文章介绍了使用trap捕获SIGINT信号并对其进行处理的步骤,以及一些 trap 语句的用法。 **脚本解析:** 1. **定义变量:** * `uphosts` 和 `downhosts` 用于存储 IP 地址是否在线的计数。 * `hosttmpfiles` 用于存储临时文件路径。 2. **循环遍历 IP 地址:** * 遍历从 192.168.152.98 到 192.168.152.102 的 IP 地址。 3. **执行 ping 命令:** * 使用 `ping` 命令尝试连接每个 IP 地址。 * 如果连接成功,打印 `$i is up.`,否则打印 `$i is down.`。 4. **记录临时文件路径:** * 当连接成功时,将临时文件路径添加到 `hosttmpfiles` 中。 * 当连接失败时,将临时文件路径添加到 `hosttmpfiles` 中。 5. **处理SIGINT信号:** * 使用 `trap` 捕获 `SIGINT`信号。 * 当收到 `SIGINT` 信号时,首先使用 `rm` 命令删除所有 `hosttmpfiles` 中的临时文件。 * 最后,使用 `exit` 命令退出脚本。 **陷阱设置:** * 使用 `trap` 捕获 `SIGINT` 信号。 * 使用 `trap` 的 `arg` 参数指定 trap 语句。 * `arg` 可以是一个函数,该函数返回需要删除的临时文件路径的字符串。 **脚本示例:** ```bash #!/bin/bash # 定义变量 uphosts=0 downhosts=0 # 循环遍历 IP 地址 for i in 192.168.152.{98..102}; do # 创建临时文件名 tmpfile=$(mktemp /tmp/ping.XXXX) # 执行 ping 命令 if ping -W 1 -c 1 $i &> /dev/null; then echo "$i is up." | tee $tmpfile else echo "$i is down." | tee $tmpfile fi # 添加临时文件路径到 hosttmpfiles 中 hosttmpfiles[${#hosttmpfiles[*]}]=$tmpfile done # 处理SIGINT信号 trap -ptrap -- '' SIGTSTPtrap -- '' SIGTTINtrap -- '' SIGTTOU # 打印结果 echo "Up hosts is $uphosts, down hosts is $downhosts." ``` **注意:** * 该脚本需要在运行时具有写权限才能创建临时文件。 * 脚本在收到 `SIGINT` 信号后,会立即退出,不会执行后续的命令。 * 该脚本展示了如何使用 trap 处理SIGINT信号并删除临时文件。

正文

首先我们先来看一段代码。

复制代码
#!/bin/bash

declare -i uphosts=0
declare -i downhosts=0

for i in 192.168.152.{98..102}; do
    if ping -W 2 -c 1 $i &>/dev/null; then
        echo "$i is up."
        let uphosts++
    else
        echo "$i is down."
        let downhosts++
    fi
done

echo "Up hosts is $uphosts, down hosts is $downhosts."
复制代码

该代码针对一个IP地址段进行ping测试,输出IP地址在线与否并做统计。为了便于观察效果,我们选择的IP地址段较短,从192.168.152.98~102,其中只有主机地址为100(即本机)的主机在线。我们运行一遍看结果。

复制代码
[root@c7-server ~]# bash trap1.sh
192.168.152.98 is down.
192.168.152.99 is down.
192.168.152.100 is up.
192.168.152.101 is down.
192.168.152.102 is down.
Up hosts is 1, down hosts is 4.
复制代码

接下来我们运行第二遍,在运行的过程中,我们使用Ctrl+c尝试终止脚本的运行。

复制代码
[root@c7-server ~]# bash trap1.sh
192.168.152.98 is down.
^C192.168.152.99 is down.
192.168.152.100 is up.
192.168.152.101 is down.
^C192.168.152.102 is down.
Up hosts is 1, down hosts is 4.
复制代码

当98和101主机地址结果显示出来以后我们立即键入Ctrl+c(在上面的输出结果上我对其进行了加粗标红),键入后99和102的输出结果立即显示出来了(由于这是代码块展示,因此无法显示出动态效果,大家看我描述脑补或者自行实验)。

我们可以发现Ctrl+c并没有终止脚本的运行,而仅仅只是终止了当前循环中的ping命令的执行。

如果我们想让脚本本身停止,就需要使用bash内置命令trap来捕获我们对脚本发出的Ctrl+c命令。

在我之前的一篇博客中《CentOS 7上的进程管理》已经有谈到通过Ctrl+c命令结束正在执行中的脚本实际上是向脚本进程发出了SIGINT信号。

因此我们需要使用trap捕获SIGINT信号并对其作出反应(在这里是尝试结束脚本的执行)。

trap语法如下。

trap [-lp] [[arg] signal_spec ...]

arg:当接受到指定的信号以后将要执行的命令;

signal_spec:具体的信号;

-l:列出所有的信号,类似于“kill -l”;

-p:打印出目前已经设置的陷阱,仅键入trap命令也有该效果。

复制代码
[root@c7-server ~]# trap
trap -- '' SIGTSTP
trap -- '' SIGTTIN
trap -- '' SIGTTOU
[root@c7-server ~]# trap -p
trap -- '' SIGTSTP
trap -- '' SIGTTIN
trap -- '' SIGTTOU
复制代码

因此我们只需要在原本的脚本的顶部(shebang下面)写入这样的陷阱即可。

复制代码
[root@c7-server ~]# cat trap1.sh 
#!/bin/bash

trap "exit" SIGINT
declare -i uphosts=0
declare -i downhosts=0
... ...
复制代码

结果如下,当脚本一收到SIGINT信号,立即结束脚本,即便循环还未停止。

[root@c7-server ~]# bash trap1.sh 
192.168.152.98 is down.
^C[root@c7-server ~]# 
[root@c7-server ~]#

我们再来看一个更有趣的例子。

假设存在一个脚本,该脚本在运行的过程中会创建各种临时文件,临时文件的路径被保留,脚本执行完毕后自动删除临时文件。为了使得脚本执行遇到中断时,临时文件也可以被清除,我们可以引入trap。注意,这个案例中trap的arg也可以是一个函数。

复制代码
#!/bin/bash

declare -a hosttmpfiles
trap "mytrap" INT

mytrap() {
    echo "Quit"
    rm -f ${hosttmpfiles[@]}
    exit 1
}

for i in 192.168.152.{98..102}; do
    tmpfile=$(mktemp /tmp/ping.XXXX)
    if ping -W 1 -c 1 $i &> /dev/null; then
        echo "$i is up." | tee $tmpfile
    else
        echo "$i is down." | tee $tmpfile
    fi
    hosttmpfiles[${#hosttmpfiles[*]}]=$tmpfile
done

rm -f ${hosttmpfiles[@]}
复制代码

但是这个脚本有一个缺陷,在某些时刻我们键入Ctrl+c时,最新创建的临时文件路径还未进入数组变量hosttmpfiles,这会导致在删除的时候遗漏一个临时文件。

对于信号捕捉(陷阱)trap的简单介绍到此为止。

与[转帖]Bash脚本编程学习笔记11:信号捕捉相似的内容:

[转帖]Bash脚本编程学习笔记11:信号捕捉

首先我们先来看一段代码。 #!/bin/bash declare -i uphosts=0 declare -i downhosts=0 for i in 192.168.152.{98..102}; do if ping -W 2 -c 1 $i &>/dev/null; then echo "$

[转帖]Bash脚本编程学习笔记02:脚本基础和bash配置文件

脚本基础 参考资料:Shell Scripts (Bash Reference Manual) 不严谨地说,编程语言根据代码运行的方式,可以分为两种方式: 编译运行:需要先将人类可识别的代码文件编译成机器可运行的二进制程序文件后,方可运行。例如C语言和Java语言。 解释运行:需要一个编程语言的解释

[转帖]Bash脚本编程学习笔记03:算术运算

https://www.cnblogs.com/alongdidi/p/bash_arithmetic_expression.html 简介 Bash所支持的算术运算和C语言是一样的,这里指的是操作符(operator)以及它们的优先级(precedence)、结合性(associativity)和

[转帖]Bash脚本编程学习笔记04:测试命令test、状态返回值、位置参数和特殊变量

Bash脚本编程学习笔记04:测试命令test、状态返回值、位置参数和特殊变量 我自己接触Linux主要是大学学习的Turbolinux --> 根据《鸟哥的Linux私房菜:基础篇》(第三版) --> 马哥的就业班课程。给我的感觉是这些课程对于bash的讲解,理论上是不够的,但是限于时间、篇幅和精

[转帖]Bash脚本编程学习笔记04:测试命令test、状态返回值、位置参数和特殊变量

https://www.cnblogs.com/alongdidi/p/test_exitStatus_positionalAndSpecialParameter.html 我自己接触Linux主要是大学学习的Turbolinux --> 根据《鸟哥的Linux私房菜:基础篇》(第三版) --> 马

[转帖]Bash脚本编程学习笔记03:算术运算

https://www.cnblogs.com/alongdidi/p/bash_arithmetic_expression.html 简介 Bash所支持的算术运算和C语言是一样的,这里指的是操作符(operator)以及它们的优先级(precedence)、结合性(associativity)和

[转帖]Bash脚本编程学习笔记05:用户交互与脚本调试

https://www.cnblogs.com/alongdidi/p/read_and_bash_debug.html 用户交互 在《学习笔记04》中我们有提到位置参数,位置参数是用来向脚本传递参数的一种方式。还有一种方式,是read命令。 [root@c7-server ~]# read nam

[转帖]Bash脚本编程学习笔记06:条件结构体

简介 在bash脚本编程中,条件结构体使用if语句和case语句两种句式。 if语句 单分支if语句 if TEST; then CMD fi TEST:条件判断,多数情况下可使用test命令来实现,返回值为0的话则执行CMD,否则就离开该条件结构体,脚本继续往下执行。 [root@c7-serve

[转帖]Bash脚本编程学习笔记07:循环结构体

https://www.cnblogs.com/alongdidi/p/bash_loop_construct.html 本篇中涉及到算术运算,使用了$[]这种我未在官方手册中见到的用法,但是确实可用的,在此前的博文《Bash脚本编程学习笔记03:算术运算》中我有说明不要使用,不过自己忘记了。大家还

[转帖]Bash脚本编程学习笔记08:函数

https://www.cnblogs.com/alongdidi/p/bash_function.html 官方资料:Shell Functions (Bash Reference Manual) 简介 正如我们在《Bash脚本编程学习笔记06:条件结构体》中最后所说的,我们应该把一些可能反复执行