【Shell编程】信号处理

时间:2021-08-13 14:44来源:未知 作者:中博IT教育

信号控制 一 信号说明 在脚本执行过程中, 可能会被一些键盘操作快捷方式所打断, 影响脚本运行 # HUP(1): 挂起、睡眠, 本信号在用户终端连接(正常或非正常)结束时发出, 通常是在终端的
信号控制
一 信号说明
在脚本执行过程中, 可能会被一些键盘操作快捷方式所打断, 影响脚本运行
 
# HUP(1):  挂起、睡眠, 
本信号在用户终端连接(正常或非正常)结束时发出, 通常是在终端的控制进程结束时, 通知同一session内的各个作业, 这时它们与控制终端不再关联。
 
登录Linux时,系统会分配给登录用户一个终端(Session)。在这个终端运行的所有程序,包括前台进程组和后台进程组,一般都 属于这个 Session。当用户退出Linux登录时,前台进程组和后台有对终端输出的进程将会收到SIGHUP信号。这个信号的默认操作为终止进程,因此前台进 程组和后台有终端输出的进程就会中止。不过可以捕获这个信号,比如wget能捕获SIGHUP信号,并忽略它,这样就算退出了Linux登录,wget也 能继续下载。
 
此外,对于与终端脱离关系的守护进程,这个信号用于通知它重新读取配置文件。
 
# INT(2):  中断, 通常因为按下ctrl+c而产生的信号,用于通知前台进程组终止进程。
# QUIT(3): 退出,和SIGINT类似, 但由QUIT字符(通常是Ctrl-\)来控制. 进程在因收到SIGQUIT退出时会产生core文件, 在这个意义上类似于一个程序错误信号。
 
# TSTP(20): 停止进行运行,通常因为按下ctrl+z而产生的信号
 
# KILL (9)
用来立即结束程序的运行. 本信号不能被阻塞、处理和忽略。如果管理员发现某个进程终止不了,可尝试发送这个信号。
# TERM(15): 
终止,是不带参数时kill默认发送的信号,默认是杀死进程,与SIGKILL不同的是该信号可以被阻塞和处理。通常用TERM信号来要求程序自己正常退出,如果进程终止不了,我们才会尝试SIGKILL。
  
# ===============了解===============
# ABRT(6): 中止, 通常因某些严重错误产生的引号   
 
# SIGCHLD 
子进程结束时, 父进程会收到这个信号。
 
如果父进程没有处理这个信号,也没有等待(wait)子进程,子进程虽然终止,但是还会在内核进程表中占有表项,这时的子进程称为僵尸 进程。这种情 况我们应该避免(父进程或者忽略SIGCHILD信号,或者捕捉它,或者wait它派生的子进程,或者父进程先终止,这时子进程的终止自动由init进程 来接管)。
 
# 更多详见:man 7 signal
二 捕捉信号
我们可以用trap命令捕捉信号(trap命令并不能捕获所有信号,但是常用信号HUP、INT、QUIT、TERM都是可以捕获的),执行我们规定的操作
 
# 操作1:捕捉信号、执行引号内的操作
trap "echo 已经识别中断信号:ctrl+c" INT
 
# 示例2:捕捉信号、不执行任何操作
trap "" INT  
 
# 示例3:也可以同时捕获多个信号
trap "" HUP INT QUIT TSTP
例1:
 
[root@egon test]# cat m.sh 
#!/bin/bash
 
trap "echo 已经识别到中断信号:ctrl+c" INT
trap 'echo 已经识别到中断信号:ctrl+\\' QUIT
trap 'echo 已经识别到中断信号:ctrl+z' TSTP
 
read -p "请输入你的名字: " name
echo "你的名字是:$name"
[root@egon test]# chmod +x m.sh 
[root@egon test]# ./m.sh 
请输入你的名字: ^C已经识别到中断信号:ctrl+c
^C已经识别到中断信号:ctrl+c
^C已经识别到中断信号:ctrl+c
^\已经识别到中断信号:ctrl+\
^\已经识别到中断信号:ctrl+\
^Z已经识别到中断信号:ctrl+z
^Z已经识别到中断信号:ctrl+z
egon
你的名字是:egon
[root@egon test]#
例2:
 
#!/bin/bash
trap "" HUP INT QUIT TSTP  # kill -HUP 当前进程的pid,也无法终止其运行
 
clear
i=0
while true
do
    [ $i == 0 ] && i=1 || i=0
 if [ $i == 0 ];then
        echo -e "\033[31m 红灯亮 \033[0m"
    else
        echo -e "\033[32m 绿灯亮 \033[0m"
    fi
    sleep 1
    clear
done
可以使用kill -9终止以上进程
 
 
 
##三 关于HUP信号
 
    要了解Linux的HUP信号,需要从hangup说起
 
在 Unix 的早期版本中,每个终端都会通过 modem 和系统通讯。
当用户 logout 时,modem 就会挂断(hang up)电话。 
同理,当 modem 断开连接时,就会给终端发送 hangup 信号来通知其关闭所有子进程。 
    综上,我们知道,当用户注销(logout)或者网络断开或者终端关闭时,终端都会收到Linux HUP信号(hangup)信号,然后终端在结束前会关闭其所有子进程。
 
    如果我们想让我们的进程在后台一直运行,不要因为用户注销(logout)或者网络断开或者终端关闭而一起被干掉,那么我们有两种解决方案
 
方案1:让进程忽略Linux HUP信号
 
方案2:让进程运行在新的会话里,从而成为不属于此终端的子进程,就不会在当前终端挂掉的情况下一起被带走。
 
 
 
###3.1 nohup命令
 
    针对方案1,我们可以使用nohup命令,nohup 的用途就是让提交的命令忽略 hangup 信号,该命令通常与&符号一起使用,nohup 的使用是十分方便的,只需在要处理的命令前加上 nohup 即可。
 
3.2 setsid命令
     针对方案1,我们还可以用setsid命令实现,原理与3.1是一样的,setid是直接将进程的父pid设置成1,即让运行的进程归属于init的子进程,那么除非init结束,该子进程才会结束,当前进程所在的终端结束后并不会影响进程的运行
 
# 1、在终端2中执行命令
[root@egon ~]# setsid ping www.baidu.com  # 也可以在后面加&符号
 
# 2、关闭终端2
 
# 3、在终端1中查看
[root@egon ~]# ps -ef |grep [p]ing
root     102335      1  0 17:53 ?        00:00:00 ping www.baidu.com
3.3 在子shell中提交任务
原理同3.2
 
# 1、在终端2中执行命令
[root@egon ~]# (ping www.baidu.com &)  # 提交的作业并不在作业列表中
 
# 2、关闭终端2
 
# 3、在终端1中查看
[root@egon ~]# ps -ef |grep [p]ing
root     102361      1  0 17:55 ?        00:00:00 ping www.baidu.com
            
可以看到新提交的进程的父 ID(PPID)为1(init 进程的 PID)
(责任编辑:中博IT教育)

苏公网安备 32030302000649号