一.Linux中信号的简介
信号是一种进程间通信机制,它给应用程序提供一种异步的软件中断,使应用程序有机会接受其他程序或终端发送的命令(即信号)。应用程序收到信号后,有三种处理方式:忽略,默认,或捕捉。 进程收到一个信号后,会检查对该信号的处理机制。如果是SIG_IGN,就忽略该信号;如果是SIG_DFT,则会采用系统默认的处理动作,通常是终止进程或忽略该信号;如果给该信号指定了一个处理函数(捕捉),则会中断当前进程正在执行的任务,转而去执行该信号的处理函数,返回后再继续执行被中断的任务。
在有些情况 下,我们不希望自己的shell脚本在运行时刻被中断,比如说我们写得shell脚本设为某一用户的默认shell,使这一用户进入系统后只能作某一项工 作,如数据库备份, 我们可不希望用户使用Ctrl c之后便进入到shell状态,做我们不希望做的事情。这便用到了信号处理。
二.Linux中信号的基础
Linux系统上通过Linux信号可以实现对脚本的控制。
常见信号 | 值 | 描述 |
1 | SIGHUP | 进程重新加载配置。httpd改端口 |
2 | SIGINT | 删除进程在内存中的数据。相当于ctrl+c, 也相当于kill -2 pid(shell的pid) |
3 | SIGQUIT | 删除鼠标在内存中的数据。ctrl+\ |
9 | SIGKILL | 强行结束单个进程(不可被阻塞)。打开gedit后台运行,另开一个shell,用-15来关闭,不行,用-9可以。但是gedit还在,因为内存中有锁定的空间。 |
15 | SIGTERM | 正常关闭进程(可能会被阻塞)。 |
17 | SIGSTOP | 无条件停止进程,但不终止进程。 |
18 | SIGCONT | 运行暂停的进程。 |
19 | SIGSTP | 暂停某个进程(不可被阻塞)。vim,shell |
20 | 把进程打入后台(可能被阻塞)。-20 shell的pid,无效,因为被阻塞,gedit可以。 |
当bash shell收到SIGHUP信号时,bash shell会退出,但在退出之前,bash shell会将SIGHUP信号传给shell启动的所有进程(包括shell脚本)。
可以通过SIGINT信号去终端bash shell,当bash shell收到SIGINT信号时,会通知shell启动的所有进程,SIGINT信号意味着Linux内核会停止将CPU处理时间分配给收到该信号的shell。
三.Linux中信号的产生
bash shell允许键盘上的按键组合产生基本的Linux信号
按键组合 | 描述 |
Ctrl+c | 发送SIGINT信号到当前正在运行的作业,让作业终止。相当于kill -2 |
Ctrl+z | 发送SIGSTP信号,将一个正在前台执行的任务进程放到后台运行,并将任务进程挂起。此时状态是STOP。相当于kill -19 |
案例:
说明:
bash shell会将shell中运行的每个进程称为作业(job)
bash shell会为每个作业分配一个唯一的作业号,方括号中[ ]的数字表示的是shell分配的作业号
Stopped表示作业在后台的状态为停止
可以使用ps命令查看已停止的作业,找到对应的PID,可以使用向作业发送SIGKILL信号的方式终止作业
说明:ps命令的第二列为PID,输入kill -9 PID即可终止进程
四.Linux中信号的捕捉,信号的屏蔽及列出中断信号与键盘的关系
默认情况下,shell脚本是不会去处理bash shell发送过来的信号
可以使用trap命令指定shell脚本可以捕捉哪些信号
当脚本收到了trap命令中列出的信号,trap命令会组织信号被shell处理,而在本地处理。
1.信号的捕捉:
信号的捕捉需要使用trap命令。
trap命令基本格式:
trap commands signals
信号以空格分隔开,可以用数值,也可以用名称。方便起见,一般使用数字。
commands表示当捕捉到信号,想要执行的shell命令。
命令用引号引起来,每次阻止到指定信号,都会执行命令。
trap "echo 'hello world'" 2 #2信号相当于"Ctrl+c",这条命令的含义是:每次按下Ctrl+c组合键时,输出hello。值的注意的是,echo命令用双引号引起来,echo命令中有空格的字符串(需要用引号引起来的字符串)用单引号引起来,用双引号会报错。
默认是换行输出,所以有一行空行。
想要不换行输出,使用“echo -n”
2.信号的屏蔽
trap "" signals
trap "" 2 #屏蔽信号2(Ctrl+c),即输入此信号没有任何回应。
信号捕捉,信号屏蔽之后,该如何恢复呢?这就涉及到下面要讲的信号恢复的内容了。
3.信号的恢复
信号恢复的方式有两种:
<1>trap : signals
trap : 2 #屏蔽信号2(Ctrl+c),即取消信号捕捉时的设置,恢复为原来的样子。
<2>trap - signals #与方法1的效果完全相同
trap - 2 #屏蔽信号2(Ctrl+c),即取消信号捕捉时的设置,恢复为原来的样子。
3.列出中断信号与键盘的关系
stty -a #列出中断信号和键盘的关系。
4.案例
案例1:编写一个脚本,实现功能:测试的时候无法终止。
案例2:捕捉脚本的退出。
退出命令为"trap 命令 EXIT
当执行结束,或者强制结束时就会执行相应的命令。
案例3:编写一个脚本,实现功能:
(1)在/tmp目录下每两秒建立一个文件,文件的命名格式为:xin_时间。时间的格式为(date +%F-%N-%M-%S)。
(2)按下Ctrl+c,删除所有这些文件并退出。
错误做法:
错误原因:(1)这里把时间定义为了一个变量,那么就不能实时获取时间。只能获取执行脚本时刻的时间,所以创建的文件只有一个。
(2)这里把捕捉信号的命令放在死循环之后,这样是不对的,这是因为while true是个死循环,这里没有跳出死循环的条件,所以,在死循环之后的捕捉信号的命令就执行不了,所以就删除不了文件。
正确做法一:
正确做法二:对正确做法一的修改(正确做法一没有查找文件,直接就删除文件,这个做法有些欠妥当。)
这里的xargs参数是把管道符之前的命令执行的结果转换为命令传递为后面rm命令。因为管道符默认是把管道符之前命令的结果作为文本传递给后面的命令。而rm命令后面删除的不是文本,所以要将其转换为命令。
五.信号控制应用之跳板机的实现
1.跳板机是什么?
现在一定规模互联网企业,往往都拥有大量服务器,如何安全并高效的管理这些服务器是每个系统运维或安全运维人员必要工作。现在比较常见的方案是搭建跳板机环境作为线上服务器的入口,所有服务器只能通过跳板机进行登陆访问。
因此需要通过终端连接到远程开发机进行工作,由于安全等因素,登录开发机时需要先登录跳板机,然后在跳板机上再实际连接开发机,如下图所示:
2.正常的登陆流程
登录跳板机成功后,在跳板机分配的终端中使用ssh命令再登录开发机,跳板机和开发机之间采用带密码的ssh验证,因此需要输入ssh私钥的密码。
跳板机就是一台服务器,维护人员在维护过程中,首先要统一登录到这台服务器上,然后从这台服务器再登录到目标设备进行维护。
但跳板机并没有实现对运维人员操作行为的控制和审计,使用跳板机过程中还是会有误操作、违规操作导致的操作事故,一旦出现操作事故很难快速定位原因和责任人。
3.跳板机脚本的实现(这里的主要技术就是实现跳板机到内部电脑的跳转)
脚本的功能:外部电脑通过跳板机连接内部电脑,如果外部电脑登陆的是root用户,则不能实现跳转,如果外部电脑登陆的是其他普通用户,则可以进行无密连接到内部电脑的特定IP,或者退出(此时信号是屏蔽状态)
ssh远程登陆机器时,会自动执行/etc/profile.d目录中的脚本
实验环境:外部电脑IP172.25.254.83,跳板机IP172.25.254.183,内部电脑IP172.25.254.133
大体步骤有下面的三步:
<1>做到跳板机的普通用户(这里以student用户为例)与内部电脑的无密连接。
(1)内部电脑:172.25.254.133
(2)内部电脑:172.25.254.133
(3)内部电脑:172.25.254.133
(4)跳板机:172.25.254.183。进行测试
<2>在跳板机上(172.25.254.183)编写脚本:需要编写两个脚本
脚本1实现跳转。主要技术:
(1)trap处理信号
(2)echo显色
(3)case条件判断
脚本2进行用户判断
<3>测试
在跳板机上(172.25.254.183)将user.sh这个脚本放到/etc/profile.d目录中,自动执行此脚本,即自动判断该用户是普通用户还是root用户。
进行跳板机(172.25.254.183)和内部电脑(172.25.254.133)之间的测试
进行外部电脑(172.25.254.83),跳板机(172.25.254.183)和内部电脑(172.25.254.133)之间的测试
从上面这张图可以看出,信号做到了屏蔽。
扩展:脚本2的第二种写法:封装为函数
值的注意的是,第二个menu必须写在最前面,否则会报错。
clear表示清屏。