scr*_*apy 14 linux bash bash-trap
打开一个名为"伏藏"终端,并运行创建的文件callback.sh 用/bin/bash callback.sh.
cat callback.sh
#!/bin/bash
myCallback() {
echo "callback function called at $(date)"
}
trap myCallback SIGUSR1
sleep 20
Run Code Online (Sandbox Code Playgroud)打开一个名为"termB"的新终端并运行:
pkill -USR1 -f callback.sh
Run Code Online (Sandbox Code Playgroud)在termA中20秒后显示以下内容; 它永远不会在termA中显示:
callback function called at Mon Nov 19 08:21:52 HKT 2018
Run Code Online (Sandbox Code Playgroud)
结论证实,当Bash在前台执行外部命令时,它不处理任何接收的信号,直到前台进程终止(参见信号陷阱).
做一点改变callback.sh:
cat callback.sh
#!/bin/bash
myCallback() {
echo "callback function called at $(date)"
}
trap myCallback SIGUSR1
while true; do
read -p "please input something for foo: " foo
done
Run Code Online (Sandbox Code Playgroud)
添加无限while循环并删除sleep 20.
打开一个名为"特玛"终端,运行创建的文件callback.sh用/bin/bash callback.sh; 第一次,信息立即弹出.
please input something for foo:
Run Code Online (Sandbox Code Playgroud)打开一个名为"termB"的新终端并运行pkill -USR1 -f callback.sh; 第一次,信息在termA中立即弹出.
callback function called at Mon Nov 19 09:07:14 HKT 2018
Run Code Online (Sandbox Code Playgroud)问题1: callback.sh包含无限循环.这如何解释以下内容?
在前台进程终止之前,它不处理任何接收到的信号
在这种情况下,前台进程永远不会终止.
继续在termB中,pkill -USR1 -f callback.sh第二次运行.
callback function called at Mon Nov 19 09:07:14 HKT 2018
Run Code Online (Sandbox Code Playgroud)
上面的信息再次在termA中立即弹出.
问题2:没有please input something for foo:在termA中显示,转到termB,pkill -USR1 -f callback.sh第三次运行,以下信息再次显示在termA中.
callback function called at Mon Nov 19 09:07:24 HKT 2018
Run Code Online (Sandbox Code Playgroud)
仍然没有please input something for foo:在termA中显示.
为什么信息会please input something for foo:冻结?
在解释你的问题之前,先介绍一下read命令的工作方式.它读取输入数据stdin直到EOF遇到.可以read肯定地说,当从磁盘上读取文件时,对命令的调用是非阻塞的.但是当stdin连接到终端时,命令将阻塞,直到用户输入内容为止.
关于信号处理如何工作的简单解释.请参见下面的代码片段中C这只是操作SIGINT(又名.CTRL+C)
#include <stdio.h>
#include <signal.h>
/* signal handler definition */
void signal_handler(int signum){
printf("Hello World!\n");
}
int main(){
//Handle SIGINT with a signal handler
signal(SIGINT, signal_handler);
//loop forever!
while(1);
}
Run Code Online (Sandbox Code Playgroud)
它将注册信号处理程序,然后进入无限循环.当我们点击时Ctrl-C,我们都同意信号处理程序signal_handler()应该执行并"Hello World!"打印到屏幕上,但程序处于无限循环中.为了打印"Hello World!"它必须是它打破循环执行信号处理程序的情况,对吧?所以它应该退出循环以及程序.让我们来看看:
gcc -Wall -o sighdl.o signal.c
./sighdl.o
^CHello World!
^CHello World!
^CHello World!
^CHello World!
^CHello World!
^CHello World!
^CHello World!
^CHello World!
^CHello World!
Run Code Online (Sandbox Code Playgroud)
正如输出所示,每次我们发出Ctrl-C,"Hello World!"打印,但程序返回无限循环.只有在发出SIGQUIT信号Ctrl-\后,程序才真正退出.根据您的ulimit设置,它会转储核心或打印出收到的信号.
虽然循环将退出的解释是合理的,但它没有考虑信号处理的主要原因,即异步事件处理.这意味着信号处理程序的行为超出了程序控制的标准流程; 事实上,整个程序保存在一个上下文中,并且只为信号处理程序创建一个新的上下文来执行.一旦信号处理程序完成其动作,就会切换回上下文并开始正常的执行流程(即while(1)).
要回答你的问题,
结论证实,当bash在前台执行外部命令时,它不会处理在前台进程终止之前收到的任何信号
这里要注意的关键是外部命令部分.在第一种情况下,sleep外部进程在哪里,但在第二种情况下,read是shell本身的内置进程.因此,在这两种情况下,信号传播到这两者都不同
type read
read is a shell builtin
type sleep
sleep is /usr/bin/sleep
Run Code Online (Sandbox Code Playgroud)
1.打开一个名为termA的终端,并首次使用/ bin/bash callback.sh运行创建的文件callback.sh,该信息立即弹出.
是的,这种行为是预期的.因为此时只定义了函数,并且陷阱处理程序已注册到函数中,myCallback并且脚本中尚未收到信号.随着执行顺序的进行,read第一次抛出来自提示的消息.
2.打开一个名为termB并在
pkill -USR1 -f callback.sh第一次运行的新终端,该信息会立即在termA中弹出
是的,当read命令正在等待字符串后跟Enter信号指示的键EOF,它接收SIGUSR1来自另一个终端的信号,保存当前执行上下文并且控制切换信号处理程序,该信号处理程序打印具有当前日期的字符串.
处理程序完成执行后,上下文将恢复到命令仍在等待输入字符串的while循环read.在read命令成功之前,所有后续信号陷阱都只会在信号处理程序内打印字符串.
在termB中继续,
pkill -USR1 -f callback.sh第二次运行.
与前面解释的相同,read命令在while循环中没有完成一次,只有在成功读取字符串时,循环的下一次迭代才会启动,并且会抛出新的提示消息.
图像源:Michael KerrisK的Linux编程接口