一、概述

我们在上一章当中示例了检测ip地址是否在线的脚本,但是有一个问题,运行的过程中,无论使用Ctrl+c怎么制止,并没有什么卵用,还是继续运行,直到将最后一个IP地址ping完,无法制止,只是将当前的ping操作结束,下一个ping操作就要运行,但是如果连续的按下快捷键,总有一个信号捕捉到,但只有被当前进程的脚本捕捉到才能够停止,而不是ping进程,这就是信号。

我们也可以手动定制信号捕捉的功能,那么如何自定义信号捕捉的处理,那么在ping操作时,由于信号捕捉不到,那么能不能在捕捉信号之后做出相应的处理操作,对于bash而言这是可以的,在系统当中有一个trap命令,通过部署一个陷阱捕捉到信号,或者激发其某个事件进行捕捉处理。

我们可使用-l选项来列出可捕捉的所有信号。

# trap -l
 1) SIGHUP   2) SIGINT   3) SIGQUIT  4) SIGILL   5) SIGTRAP
 6) SIGABRT  7) SIGBUS   8) SIGFPE   9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG  24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF 28) SIGWINCH    29) SIGIO   30) SIGPWR
31) SIGSYS  34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX    

不过,使用kill -l也是获得相同的结果,不过要想了解其信号意义,我们可通过man手册来进行查看。

信号捕捉:
    列出信号:
        trap -l
        kill -l
        man 7 signal

信号是进程间通信间的一种机制,而trap命令可以让bash脚本自定义如何捕捉信号,但需要注意的是,不能捕捉TERMKILL的信号,因为捕捉信号的意义在于一旦捕捉到之后能够作出什么操作,因此一般捕捉到信号为HUP以及INT等,当然其它的信号也可以捕捉,但是没有以上这两个用的那么频繁。

    常用的信号:
        HUP, INT

示例:

#!/bin/bash

trap  'echo "Dou ni wan"' INT

for i in {1..254}; do
    if ping -W1 -c1 192.168.$i.1 &> /dev/null; then
        echo "192.168.$i.1 is up."
    else
        echo "192.168.$i.1 is down."
    fi
done
# bash trap.sh 
192.168.1.1 is down.
192.168.2.1 is down.
^CDou ni wan
192.168.3.1 is down.
^CDou ni wan
192.168.4.1 is down.
^CDou ni wan
192.168.5.1 is down.
^CDou ni wan
192.168.6.1 is down.

从以上的运行结果看出,一旦发出Ctrl+c就是INT信号后,会显示出Dou ni wan,但是其实并没有停止其ping进程,只是停止了当前的ping,而下一个循环的ping开始运行,如果彻底退出的当前bash进程的话,要用另一种方式。

#!/bin/bash

trap  'echo "quit"; exit 1' INT

for i in {1..254}; do
    if ping -W1 -c1 192.168.$i.1 &> /dev/null; then
        echo "192.168.$i.1 is up."
    else
        echo "192.168.$i.1 is down."
    fi
done

那么这就是trap命令的意义,能够其捕捉信号,且捕捉到信号后,使用所定义好的命令来进行处理如何进行,那么以上的信号处理就是显示quit并退出shell进程。

那么trap命令的方法很简单,后面跟上其参数,并跟上信号声明,而一旦捕捉到其信号之后,我们作出什么样的处理操作,而它的命令用法为:

trap 'COMMAND' SIGNALS

我们可以使用以函数中所定义好的命令的形式来对trap进行定义而后对其进行捕捉。

#!/bin/bash
#

trap 'mytrap' INT
mytrap() {
    echo "Quit"
    exit 1
}

for i in {1..254}; do
    if ping -W1 -c1 192.168.$i.1 &> /dev/null; then
        echo "192.168.$i.1 is up"
    else
        echo "192.168.$i.1 is down"
    fi
done

而在每次ping操作完成之后,可创建其临时文件保存其相关的信息。放在循环内部,每一次创建完成可保证将其可以删除,也需要保证三叉输出。

但是这样的话会创建无数个临时文件,我们需要创建其数组用来其追加到最后一个元素中,遇到终止信号时将其文件进行删除。

#!/bin/bash
#

declare -a hosttmpfiles
trap 'mytrap' INT
mytrap() {
    echo "Quit"
    rm -f ${hosttmpfiles[@]}
    exit 1
}

for i in {1..254}; do
    tmpfile=$(mktemp /tmp/ping.XXXXXX)
    if ping -W1 -c1 192.168.$i.1 &> /dev/null; then
        echo "192.168.$i.1 is up" | tee $tmpfiles
    else
        echo "192.168.$i.1 is down" | tee $tmpfiles
    fi
    hosttmpfiles[${#hosttmpfiles[*]}]=$tmpfile
done

echo ${hosttmpfiles[@]}

在信号捕捉中的函数内部可以写出一些复杂的处理逻辑,包括退出及删除未处理的文件等。

二、在bash中使用ASCII颜色

echo命令中如何进行着色是一件很简单的事情,关于相关的教程网上也是一抓一大把,那么其着色定义格式为:

\033[31m hello \033[0m

以上这种格式表示随后控制的字体显示为什么颜色,以及在那里进行关闭,如果没有关闭的话随后都是以这个颜色进行显示,除非到下一个命令有自己的输出流时才能结束,为了避免这种影响,所以要在后面需加上\033[0m,表示不要影响其后面的着色,就在这个范围内进行着色。

而那两个数字也有个不同的意义。

    ##m:
        左侧#:
            3: 前景色;
            4: 背景色;
        右侧#: 颜色种类
            1, 2, 3, 4, 5, 6, 7

如果使用的是单个数字的话,会改变文本的格式,例如加粗或闪烁等。

    #m:
        加粗、闪烁等功能;

多种控制符,可组合使用,彼此间用分号隔开;
echo -e "\033[42;35;5,hello world\033[0m"