• Bash脚本编程学习笔记09:信号捕捉


    简介

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

    #!/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的简单介绍到此为止。

  • 相关阅读:
    EntityFramework系列:MySql的RowVersion
    EntityFramework系列:SQLite.CodeFirst自动生成数据库
    怎么回事呢?
    为蛇么不现实
    发布到个人主页
    作别
    budao 首页
    中午吃饱了
    作业写好了吗?
    分类
  • 原文地址:https://www.cnblogs.com/alongdidi/p/bash_trap.html
Copyright © 2020-2023  润新知