【Linux】信号处理

发布于:2025-02-11 ⋅ 阅读:(55) ⋅ 点赞:(0)

一、Linux系统信号

1、常见的系统信号

常见的Linux系统信号
信号 描述
1 SIGHUP 挂起(hang up)进程
2 SIGINT 中断进(interrupt)程
3 SIGQUIT 停止(stop)进程
9 SIGKILL 无条件终止(terminate)进程
15 SIGTERM 尽可能终止进程
18 SIGCONT 继续运行停止的进程
19 SIGSTOP 无条件停止,但不终止进程
20 SIGTSTP 停止或暂停(pause),但不终止进程

2、两种基本的信号

中断进程Ctrl+C

Ctrl+C生成的是SIGINT信号,它会将其发送给当前在shell中运行的所有进程。

暂停进程Ctrl+Z

Ctrl+Z生成的是SIGTSTP信号,停止shell中运行的任何进程。

停止(stopping)进程和终止(terminating)进程不同,前者是让程序继续驻留在内存中,但依然能从上次停止的位置继续运行。

方括号里的数字 1 是shell分配的作业号

shell将运行的各个进程称为作业,并且为作业在当前shell内分配了唯一的作业号。作业号从1开始,接着是2,依次递增。

如果shell会话中存在一个已经停止的作业,那么在退出shell时,bash会给出提醒。

此时只需要再输入一遍exit命令即可,shell就会退出,并终止已停止的作业。

也可以用kill命令发送SIGKILL(9)信号将其终止。

ps命令查看已停止的作业。

 3、捕获信号trap命令

trap命令可以让shell脚本需要侦测并拦截的Linux信号,如果脚本收到了trap命令中列出的信号,则该信号不再由shell处理,而是由本地处理。

格式:

trap commands signals

commands:列出想要shell执行的命令;

signals:列出想要捕获的信号(多个信号之间用空格分隔)。指定信号时可用信号的值或信号名。

#!/bin/bash

trap "echo '捕获到了Ctrl+C信号'" SIGINT

echo "测试脚本"

count=1
while [ $count -le 5 ]
do
  echo "这是第$count次循环"
  sleep 1
  count=$[ $count + 1 ]
done

echo "测试脚本结束!"
exit

此shell脚本每次侦测到Ctrl+C信号(SIGINT)时,trap命令都会打印出一条“捕获”信息。通过此,可以阻止用户通过Ctrl+C停止脚本。 

如果shell脚本中的命令被信号中断,使用带有指定命令的trap未必能让被中断的命令继续执行。为了保证脚本中的关键操作不被打断,可以使用带有空操作命令的trap以及要捕获的信号列表。

如:trap " " SIGINT

此形式的trap命令可以让shell脚本完全忽略SIGINT信号,继续执行重要工作。 

捕获shell脚本在退出时的信号

在trap命令后加上EXIT信号即可。

#!/bin/bash

trap "echo '此脚本已执行完,马上退出……'" EXIT

echo "测试脚本"

count=1
while [ $count -le 5 ]
do
  echo "这是第$count次循环"
  sleep 1
  count=$[ $count + 1 ]
done

echo "测试脚本结束!"
exit
正常退出 

 

提前退出

 

修改或移除信号捕获

要想在shell脚本中不同位置进行不同的信号捕获处理,只需要重新使用带有新选项的trap命令即可。

#!/bin/bash

trap "echo '捕获到Ctrl+C信号'" SIGINT

echo "第1项测试"

count=1
while [ $count -le 5 ]
do
  echo "这是第$count次循环"
  sleep 1
  count=$[ $count + 1 ]
done

trap "echo '捕获到Ctrl+Z信号'" 20

echo "第2项测试"

count=1
while [ $count -le 4 ]
do
  echo "这是第$count次循环"
  sleep 1
  count=$[ $count + 1 ]
done

exit

查看被捕获的信号

在交互式shell会话中使用 trap -p 查看被捕获的信号。如果什么都没显示,说明shell会话按照默认方式处理了信号。

移除已设置好的信号捕获

 在trap命令与希望恢复默认行为的信号列表之间加上两个连字符,如 trap -- SIGINT;也可以在trap命令后使用单连字符来恢复信号的默认行为,如 trap - SIGINT

#!/bin/bash

trap "echo '捕获到Ctrl+C信号'" SIGINT

echo "第1项测试"

count=1
while [ $count -le 5 ]
do
  echo "这是第$count次循环"
  sleep 1
  count=$[ $count + 1 ]
done

trap -- SIGINT # 等同于trap - SIGINT
echo "移除信号捕获。"

echo "第2项测试"

count=1
while [ $count -le 4 ]
do
  echo "这是第$count次循环"
  sleep 1
  count=$[ $count + 1 ]
done

exit

在移除信号捕获后,一旦执行Ctrl+C,就会立即停止执行脚本。 

二、后台运行脚本

 使用 ps -e 命令,查看系统后台运行的进程。

在后台运行模式中,进程运行时不和终端会话的STDIN、STDOUT、STDERR关联。

1、后台运行脚本

在脚本名后面加上 & 即可,它会将脚本与当前shell分离开,并将脚本作为一个独立的后台进程运行。

方括号里的数字 1 是shell分配给后台进程的作业号,数字 109747 是Linux系统为进程分配的进程ID(PID)。Linux系统中的每个进程都必须有唯一的PID。

注:如下所示,当后台进程运行时,它仍然会使用终端显示器来显示STDOUT和STDERR的消息。

 

如下所示,后台运行时可以执行其它命令 

三、在非控制台下运行脚本

 退出终端会话后,仍然想让脚本一直在后台运行直到结束。可以使用 nohup 命令实现。

nohup命令可以阻断发给特定进程的SIGHUP信号,当退出终端会话时,便可以避免进程退出。

格式:nohup command

 当使用nohup命令时,如果关闭终端会话,shell脚本会忽略其发送的SIGHUP信号。由于nohup命令会解除终端与进程之间的关联,因此进程不再同STDOUT和STDERR绑定在一起。为了保存该命令产生的输出,nohup命令会自动将STDOUT和STDERR产生的消息重定向到 nohup.out 的文件中。(nohup.out文件一般在当前工作目录下,不然就在$HOME目录下)

如果使用nohup运行了另一个命令,则该命令的输出会被追加到已有的nohup.out文件中。

四、作业控制

 kill命令可以杀死作业,如果要重启已停止的进程,需要向其发送SIGCONT信号。

作业控制包括启动、停止、杀死恢复

1、查看作业jobs命令

jobs 命令允许用户查看shell当前正在处理的作业。

#!/bin/bash

echo "脚本的PID:$$" # $$是一个特殊变量,它表示shell进程的进程ID(PID)

count=1
while [ $count -le 6 ]
do
  echo "这是第$count次循环。"
  sleep 8
  count=$[ $count + 1 ]
done

echo "脚本结束……"
exit

 运行脚本后,使用 Ctrl+Z 组合键停止脚本。

然后在后台又运行一次此脚本,并将输出重定向到文件 test1.out 中。

 使用 jobs 命令查看分配给shell的作业。

如下图所示,加号 + 表示默认作业。如果作业控制命令没有指定作业号,则引用该默认作业。

减号 - 表示在默认作业结束后成为下一个默认作业。

任何时候,不管shell中运行着多少作业,带加号和减号的作业都有且只能有一个。

jobs -l 查看作业的进程号。

 

jobs命令选项
-l 列出进程的PID以及作业号
-n 只列出上次shell发出通知后状态发生改变的作业
-p 只列出作业的PID
-r 只列出运行中的作业
-s 只列出已停止的作业

删除已停止的作业

2、重启已停止的作业bg命令

可以将已停止的作业作为后台进程或前台进程重启(注:前台进程重启后会接管当前正在使用的终端)

后台模式重启:bg命令

注:当作业被转入后台模式后,并不会显示其PID。

如果存在多个作业,需要在bg命令后加上作业号,如 bg 2

前台模式重启:fg命令

如下所示,因为作业是在前台运行的,所以直到该作业完成后,命令行界面的提示符才会出现。


网站公告

今日签到

点亮在社区的每一天
去签到