c - 将 SIGINT 发送到运行脚本的分叉 exec 进程不会杀死它
问题描述
我正在用 C 编写 shell 应用程序,遇到了一个问题,即发送 SIGINT 来处理正在运行的脚本不会停止它。
将相同的信号发送到正常的可执行文件就可以了。
例子:
仅模仿长工作脚本 (work.sh) 的 Bash 脚本:
#! /bin/bash
COUNTER=0
while true
do
((COUNTER+=1))
echo "#${COUNTER} Working..."
sleep 1
done
C代码:
int main() {
pid_t pid = fork();
if (pid == 0) {
char* cmds[] = { "./work.sh", NULL };
if (execvp(cmds[0], cmds) == -1) {
exit(1);
}
} else {
sleep(5);
kill(pid, SIGINT);
}
return 0;
}
发送信号后,主进程结束,但脚本继续打印。
脚本中的信号处理是否有所不同?您需要如何停止子进程而忽略正在运行的内容?
解决方案
一个解法:
work.sh
在脚本顶部添加这一行trap exit SIGINT
以获得显式的 SIGINT 处理程序:
#! /bin/bash
trap exit SIGINT
COUNTER=0
while true
do
((COUNTER+=1))
echo "#${COUNTER} Working..."
sleep 1
done
运行work
可执行文件现在打印:
#1 Working...
#2 Working...
#3 Working...
#4 Working...
#5 Working...
之后它返回到 shell。
问题:
我在 Unix stackexchange 上的这个问题的评论中发现了这个网页链接(为了完整起见,这里还有在接受的答案中链接的网页。)这是一个可以解释发生了什么的引用:
bash 是少数几个在处理 SIGINT/SIGQUIT 传递时实现等待和合作退出方法的 shell 之一。在解释脚本时,在接收到 SIGINT 时,它不会立即退出,而是等待当前运行的命令返回,并且只有在该命令也被该 SIGINT 杀死时才退出(通过使用 SIGINT 杀死自己)。这个想法是,例如,如果您的脚本调用 vi,并且您在 vi 中按 Ctrl+C 以取消操作,则不应将其视为中止脚本的请求。
所以想象你正在编写一个脚本,并且该脚本在收到 SIGINT 后正常退出。这意味着如果从另一个 bash 脚本调用该脚本,Ctrl-C 将不再中断该另一个脚本。
这种问题可以通过设计在 SIGINT 上正常退出的实际命令看到。
编辑:
我找到了另一个 Unix stackexchange答案,它可以更好地解释它。如果您查看bash(1)
手册页,则以下内容也很容易解释:
bash 运行的非内置命令将信号处理程序设置为 shell 从其父级继承的值。当作业控制无效时,除了这些继承的处理程序之外,异步命令还会忽略 SIGINT 和 SIGQUIT。
尤其是考虑到:
进入 shell 时忽略的信号不能被捕获、重置或列出。
基本上,runningwork.sh
在单独的执行环境中运行它:
当要执行除内置或 shell 函数之外的简单命令时,将在单独的执行环境中调用它。
这包括默认情况下(如果未明确存在)将忽略SIGINT
的信号处理程序。SIGQUIT
推荐阅读
- magnolia - Magnolia CMS Content App 多值和复合字段错误
- javascript - 在Javascript中循环遍历两个数组和匹配元素
- .net - 如何注入 AntiForgery 令牌?
- .htaccess - htaccess 规则使用 Cloudflare 地理定位将国家参数添加到 URL
- r - 多元回归不起作用:残差:所有 349 个残差均为 0:无残差自由度
- html - 去除 html/css 中图片的边距
- c# - 输入特定范围内的数字,当它们的总和达到 5 位数字时将它们相加
- three.js - THREE.js 斜边着色器
- java - 具有最小冲突的两个整数数组的哈希函数
- r - 将一列中的文本数据转换为R中的数字数据