Unix/Linux - 信号与捕获
你好,未来的计算机巫师们!今天,我们将深入探讨Unix/Linux信号和捕获的迷人世界。如果你是编程新手,不用担心——我会一步一步引导你完成这次冒险,就像我多年来教导无数学生一样。那么,让我们一起踏上这段激动人心的旅程吧!
什么是信号?
想象你在一个忙碌的餐厅厨房里。厨师(我们称他为Unix大厨)需要快速地与他的员工沟通。他不会在嘈杂声中大喊,而是使用一套手势信号系统。在Unix/Linux世界中,信号的作用与此类似——是进程之间快速高效沟通的一种方式。
信号是发送给程序的软件中断,用以指示发生了重要事件。这些事件可能从用户请求到异常运行时发生。
信号列表
就像Unix大厨可能有不同的手势信号表示“多放盐”、“快点”或“休息一下”,Unix/Linux系统也有用于不同目的的各种信号。让我们看看一些最常见的信号:
信号名称 | 信号编号 | 描述 |
---|---|---|
SIGHUP | 1 | 在控制终端检测到挂起或控制进程死亡 |
SIGINT | 2 | 来自键盘的中断(Ctrl+C) |
SIGQUIT | 3 | 来自键盘的退出(Ctrl+\) |
SIGKILL | 9 | 杀死信号(无法捕获或忽略) |
SIGTERM | 15 | 终止信号 |
SIGSTOP | 17, 19, 23 | 停止进程(无法捕获或忽略) |
默认行为
当一个信号发送给进程时,除非有其他指示,否则进程将采取默认行为。这些默认行为就像我们厨房员工的直觉反应。例如:
- 终止进程
- 忽略信号
- 转储核心
- 停止进程
- 继续停止的进程
发送信号
现在,让我们学习如何发送这些信号。在Unix/Linux中,我们使用kill
命令向进程发送信号。不要被这个名字骗了——kill
并不总是终止进程;这只是发送信号的一种方式。
下面是如何使用它的方法:
kill -信号名称 进程ID
例如,向进程1234发送SIGTERM信号:
kill -SIGTERM 1234
或者,使用信号编号:
kill -15 1234
捕获信号
如果我们的厨房员工能够决定如何响应Unix大厨的信号,而不是总是遵循默认反应,这在编程中就是信号捕获的作用。
在shell脚本中,我们使用trap
命令来捕捉信号并指定接收到信号时要做什么。这是基本语法:
trap 命令 信号(们)
让我们看一个例子:
#!/bin/bash
trap "echo 你好!" SIGINT SIGTERM
echo "这是一个陷阱!"
while true
do
sleep 60
done
在这个脚本中,如果它接收到SIGINT或SIGTERM,它将打印"你好!"而不是终止。就像告诉我们的厨房员工:"当厨师发出停止信号时,说'你好!'而不是真的停止。"
清理临时文件
捕获的一个常见用途是在脚本退出前清理临时文件。这里是一个例子:
#!/bin/bash
# 创建一个临时文件
temp_file=$(mktemp)
# 设置一个捕获,退出时删除临时文件
trap "rm -f $temp_file" EXIT
# 使用临时文件
echo "你好,世界!" > $temp_file
cat $temp_file
# 当脚本退出时,临时文件将被自动删除
这个脚本创建了一个临时文件,向其写入数据,从中读取数据,然后在脚本退出时自动删除它,多亏了捕获。
忽略信号
有时,你可能想要忽略某些信号。在我们的厨房比喻中,这就相当于告诉厨师:"无论你多少次示意要更多盐,我都不会再加!"
下面是如何忽略一个信号的方法:
trap "" SIGINT
这告诉脚本在接收到SIGINT信号时什么也不做。
重置捕获
如果你在捕获信号后想要恢复默认行为,你可以这样重置捕获:
trap - SIGINT
这将移除对SIGINT的捕获,恢复默认行为。
这里有一个更完整的例子:
#!/bin/bash
# 初始捕获SIGINT
trap "echo 你不能阻止我!" SIGINT
echo "试着用Ctrl+C停止我..."
sleep 10
# 现在,重置捕获
trap - SIGINT
echo "好吧,现在你可以用Ctrl+C停止我了..."
sleep 10
echo "如果你看到这句话,说明你没有阻止我!"
这个脚本首先捕获SIGINT,然后在10秒后重置捕获。就像告诉我们的厨房员工:"在10秒内忽略停止信号,然后回到正常反应。"
那么,各位!我们已经穿越了Unix/Linux信号和捕获的土地。记住,熟能生巧。试着写你自己的脚本,玩转不同的信号,很快你就能像一个真正的指挥家一样指挥你的进程乐队。快乐的编码!
Credits: Image by storyset