Shell编程——信号及trap命令

1、信号知识

1.1、信号介绍

运行Shell脚本程序时,如果按下快捷键Ctrl+c或Ctrl+x(x为其他字符)​,程序就会立刻终止运行。

在有些情况下,我们并不希望Shell脚本在运行时被信号中断,此时就可以使用屏蔽信号手段,让程序忽略用户输入的信号指令,从而继续运行Shell脚本程序。

简单地说,Linux的信号是由一个整数构成的异步消息,它可以由某个进程发给其他的进程,也可以在用户按下特定键发生某种异常事件时,由系统发给某个进程。

1.2、信号列表

在Linux下和信号相关的常见命令为kill及trap命令,本章将重点讲解如何使用trap命令,以及如何利用trap控制的跳板机脚本来使用信号。

执行kill -l或trap -l命令,可以列出系统支持的各种信号,多达64个,如图所示。
在这里插入图片描述
下面将对企业实战中Linux系统的重要信号进行说明,见表。
在这里插入图片描述
在使用信号名时需要省略SIG前缀。

通常需要忽略的信号包括HUP、INT、QUIT、TSTP、TERM等,对应的信号编号分别为1、2、3、20、15。Shell脚本中既可以用数字来代表信号,也可以使用信号的名字来代表信号,如果读者想要了解关于信号的更多知识,可以加本书的QQ交流群(本书前言中有提供)​,群里有详细的文档说明。

2、使用trap控制信号

trap命令用于指定在接收到信号后将要采取的行动,信号的相关说明前面已经提到过。trap命令的一种常见用途是在脚本程序被中断时完成清理工作,或者屏蔽用户非法使用的某些信号。在使用信号名时需要省略SIG前缀。可以在命令提示符下输入命令trap -l来查看信号的编号及其关联的名称。

trap命令的参数分为两部分,前一部分是接收到指定信号时将要采取的行动,后一部分是要处理的信号名。

trap命令的使用语法如下:

trap command signal

signal是指接收到的信号,command是指接收到该信号应采取的行动。也就是:

trap ’命令;命令’ 信号编号

trap ’命令;命令’ 信号名

范例:测试trap命令捕获Ctrl+c信号。

[root@oldboy ~]# trap 'echo oldboy' 2   #<==当执行此命令时,按Ctrl+c键,就会执行echo命令,这里结尾的2就是Ctrl+c键对应的数字信号。
 [root@oldboy ~]# ^Coldboy    #<==按Ctrl+c键后调用echo命令输出结果。

 [root@oldboy ~]# ^Coldboy    #<==按Ctrl+c键后调用echo命令输出结果。
 [root@oldboy ~]# trap "echo oldgirl" INT  #<==当执行此命令时,按Ctrl+c键,就会执行echo命令,这里结尾的INT就是Ctrl+c键对应的信号名称。

 [root@oldboy ~]# ^Coldgirl   #<==按Ctrl+c键后调用echo命令输出结果。

 [root@oldboy ~]# ^Coldgirl   #<==按Ctrl+c键后调用echo命令输出结果。

用stty -a可以列出中断信号与键盘的对应信息,如下:

[root@oldboy ~]# stty -a
speed 38400 baud; rows 20; columns 103; line = 0;
intr = ^C; quit = ^\; erase = ^? ; kill = ^U; eof = ^D; eol = <undef>; eol2 =
<undef>; swtch = <undef>;
start  =  ^Q;  stop  =  ^S;  susp  =  ^Z;  rprnt  =  ^R;  werase  =  ^W;  lnext  =  ^V;
flush = ^O; min = 1; time = 0;
-parenb -parodd cs8 -hupcl -cstopb cread -clocal -crtscts -cdtrdsr
-ignbrk  -brkint  -ignpar  -parmrk  -inpck  -istrip  -inlcr  -igncr  icrnl  ixon
-ixoff -iuclc -ixany -imaxbel
-iutf8 opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0
bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt
echoctl echoke

范例:测试按下Ctrl+c组合键而引发的INT(2)信号。

[root@oldboy ~]# trap "" 2 #<==执行动作处为空,此命令可以用来屏蔽与数字对应的Ctrl+c信号。
[root@oldboy ~]# #<==此时执行Ctrl+c键无任何反应。
[root@oldboy ~]# trap ":" 2 #<==恢复Ctrl+c信号。
[root@oldboy ~]# #<==此时可以执行Ctrl+c了。
[root@oldboy ~]# trap "echo -n 'you are typing ctrl+c'" 2
[root@oldboy ~]# ^Cyou are typing ctrl+c
[root@oldboy ~]# ^Cyou are typing ctrl+c
[root@oldboy ~]# ^Cyou are typing ctrl+c
[root@oldboy ~]# ^Cyou are typing ctrl+c

范例:同时处理多个信号。

执行任何一个对应信号的事件时,都会执行前面对应的动作,因为动作为空,所以执行后没有任何反应。

[root@oldboy ~]# trap "" 1 2 3 20 15  #<==执行这些数字信号,什么都不做。
[root@oldboy ~]# trap ":" 1 2 3 20 15 #<==执行这些数字信号,恢复对应功能。
[root@oldboy ~]# ^C
[root@oldboy ~]# trap "" HUP INT QUIT TSTP TERM #<==执行这些名称信号,什么都不做。
[root@oldboy ~]# trap ":" HUP INT QUIT TSTP TERM #<==执行这些名称信号,恢复对应功能。
[root@oldboy ~]# trap "" `echo {1..64}`        #<==屏蔽1-64的所有数字信号。

3、Linux信号及trap命令的生产应用案例

范例:开发脚本实现触发信号后清理文件功能。

脚本如下:

[root@oldboy scripts]# cat 17_4_1.sh
#! /bin/bash
#Author:oldboy training
trap "find /tmp -type f -name "oldboy_*"|xargs rm -f && exit" INT
#<==捕获Ctrl+c键后即执行find删除命令。
while true
do
    touch /tmp/oldboy_$(date +%F-%H-%M-%S) #<==在/tmp下创建文件。
    sleep 3                                      #<==休息3秒。
    ls -l /tmp/oldboy*                         #<==查看文件创建的情况。
done
[root@oldboy scripts]# sh 17_4_1.sh #<==执行脚本后,很快就会在/tmp下创建很多文件。
-rw-r--r-- 1 root root 0 922 13:41 /tmp/oldboy_2016-09-22-13-41-08
-rw-r--r-- 1 root root 0 922 13:41 /tmp/oldboy_2016-09-22-13-41-08
-rw-r--r-- 1 root root 0 922 13:41 /tmp/oldboy_2016-09-22-13-41-11
-rw-r--r-- 1 root root 0 922 13:41 /tmp/oldboy_2016-09-22-13-41-08
-rw-r--r-- 1 root root 0 922 13:41 /tmp/oldboy_2016-09-22-13-41-11
-rw-r--r-- 1 root root 0 922 13:41 /tmp/oldboy_2016-09-22-13-41-14
^C #<==按Ctrl+c键后,发现所有的文件都被清理了,说明已经调用了find清理命令。
[root@oldboy scripts]# ls -l /tmp/
总用量 4
drwx------ 2 oldboy oldboy 4096 922 13:38 ssh-YSpSS25727

范例:开发脚本,练习使用QUIT、TSTP、INT信号。

脚本如下:

[root@oldboy scripts]# cat 17_5.sh
#! /bin/bash
#Author:oldboy training
trap 'echo "you art typing Ctrl-c, sorry, script will not terminate."' INT
#<==捕获Ctrl+c键对应的信号后,执行对应快捷键时就会执行echo命令。
trap 'echo "you art typing Ctrl-\, sorry, script will not terminate."' QUIT
#<==捕获Ctrl+\键对应的信号,执行对应快捷键时就会执行echo命令。
trap 'echo "you art typing Ctrl-z, sorry, script will not terminate."' TSTP
#<==捕获Ctrl+z键对应的信号,执行对应快捷键时就会执行echo命令(实测此处没有执行echo命令)。
while true
do
    echo "Now, test signal `date`"
    sleep 5
done

测试执行结果如下:

[root@oldboy scripts]# sh 17_5.sh
Now, test signal 2016年 09月 22日 星期四 14:03:09 CST
Now, test signal 2016年 09月 22日 星期四 14:03:14 CST
^Cyou art typing Ctrl-c, sorry, script will not terminate.
#<==按下Ctrl+c键将打印这一行提示。
Now, test signal 2016年 09月 22日 星期四 14:03:15 CST
Now, test signal 2016年 09月 22日 星期四 14:03:20 CST
^\退出
you art typing Ctrl-\, sorry, script will not terminate.
#<==按下Ctrl+\键将打印这一行提示。
Now, test signal 2016年 09月 22日 星期四 14:03:21 CST
Now, test signal 2016年 09月 22日 星期四 14:03:26 CST
^Z^Z #<==按下Ctrl+z键没有打印提示,但是程序停止运行了。

范例:开发企业级Shell跳板机。要求用户登录到跳板机后只能执行管理员给定的选项动作,不允许以任何形式中断脚本而到跳板机服务器上执行任何系统命令。

参考答案1:

  • 1)首先做好ssh密钥验证(跳板机地址为192.168.33.128)​。
    将在所有机器上操作以下命令:

    [root@oldboy ~]# useradd jump                         #<==要在所有机器上操作。
    [root@oldboy ~]# echo 123456|passwd --stdin jump  #<==要在所有机器上操作。
    Changing password for user jump.
    passwd: all authentication tokens updated successfully.
    

    仅在跳板机上操作以下命令:

    [root@oldboy ~]# su - jump
    [jump@oldboy ~]$ ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa >/dev/null 2&1
    #<==生成密钥对。
    [jump@oldboy ~]$ ssh-copy-id -i ~/.ssh/id_dsa.pub 192.168.33.130
    #<==将公钥分发到其他服务器。
    The authenticity of host '192.168.33.130 (192.168.33.130)' can't be established.
    RSA key fingerprint is fd:2c:0b:81:b0:95:c3:33:c1:45:6a:1c:16:2f:b3:9a.
    Are you sure you want to continue connecting (yes/no)? yes
    Warning: Permanently added '192.168.33.130' (RSA) to the list of known hosts.
    jump@192.168.33.130's password:
    Now try logging into the machine, with "ssh '192.168.33.130'", and check in:
    
       .ssh/authorized_keys
    
    to make sure we haven't added extra keys that you weren't expecting.
    
    [jump@oldboy ~]$ ssh-copy-id -i ~/.ssh/id_dsa.pub 192.168.33.129
    #<==将公钥分发到其他服务器。
    The authenticity of host '192.168.33.129 (192.168.33.129)' can't be established.
    RSA key fingerprint is fd:2c:0b:81:b0:95:c3:33:c1:45:6a:1c:16:2f:b3:9a.
    Are you sure you want to continue connecting (yes/no)? yes
    Warning: Permanently added '192.168.33.129' (RSA) to the list of known hosts.
    jump@192.168.33.129's password:
    Now try logging into the machine, with "ssh '192.168.33.129'", and check in:
    
       .ssh/authorized_keys
    
    to make sure we haven't added extra keys that you weren't expecting.
    
  • 2)实现传统的远程连接菜单的脚本。
    菜单脚本如下:

       cat <<menu
           1)oldboy-192.168.33.129
           2)oldgirl-192.168.33.130
           3)exit
     menu
    
  • 3)利用Linux信号防止用户中断信号在跳板机上操作。
    代码如下:

    function trapper () {
        trap ':' INT  EXIT TSTP TERM HUP  #<==屏蔽这些信号。
    }
    
  • 4)用户登录跳板机后即调用脚本(不能用命令行管理跳板机)​,并且只能按管理员的要求选单。
    以下为实战内容。

    将脚本放在跳板机上:

    [root@oldboy ~]# echo '[ $UID -ne 0 ] && . /server/scripts/jump.sh' >/etc/
    profile.d/jump.sh
    [root@oldboy ~]# cat /etc/profile.d/jump.sh
    [ $UID -ne 0 ] && . /server/scripts/jump.sh
    
    [root@oldboy scripts]# cat /server/scripts/jump.sh
    #! /bin/sh
    #oldboy training
    trapper() {
        trap ':' INT  EXIT TSTP TERM HUP  #<==定义需要屏蔽的信号,冒号表示啥都不做。
    }
    main(){
        while :
        do
            trapper
            clear
            cat <<menu
              1)Web01-192.168.33.129
              2)Web02-192.168.33.130
    menu
            read -p "Pls input a num.:" num
            case "$num" in
                1)
                      echo 'login in 192.168.33.129.'
                      ssh 192.168.33.129
                      ;;
                2)
                      echo 'login in 192.168.33.130.'
                      ssh 192.168.33.130
                      ;;
                110)
                      read -p "your birthday:" char
                      if [ "$char" = "0926" ]; then
                          exit
                          sleep 3
                      fi
                      ;;)
                      echo "select error."
            esac
        done
    }
    main
    

    执行效果如下:

    [root@oldboy ~]# su - jump    #<==切到普通用户即弹出菜单,工作中直接用jump登录,即弹出菜单。
       1)Web01-192.168.33.129
       2)Web02-192.168.33.130
    Pls input a num.:
       1)Web01-192.168.33.129
       2)Web02-192.168.33.130
    Pls input a num.:1             #<==选1,则进入Web01服务器。
    login in 192.168.33.129.
    Last login: Tue Oct 11 17:23:52 2016 from 192.168.33.128
    [jump@littleboy ~]$           #<==按Ctrl+D键退出到跳板机服务器,且再次弹出菜单。
       1)Web01-192.168.33.129
       2)Web02-192.168.33.130
    Pls input a num.:2             #<==选2,则进入Web02服务器。
    login in 192.168.33.130.
    Last login: Wed Oct 12 23:30:14 2016 from 192.168.33.128
    [jump@oldgirl ~]$             #<==按Ctrl+D键退出到跳板机服务器,且再次弹出菜单。
       1)Web01-192.168.33.129
       2)Web02-192.168.33.130
    Pls input a num.:110           #<==选110,则进入跳板机命令提示符
    your birthday:0926             #<==需要输入特别码才能进入,这里是管理员通道,密码要保密呦。
    [root@oldboy scripts]#         #<==跳板机管理命令行。
    
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值