微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Bash:当子脚本捕获SIGINT时,为什么父脚本不能在SIGINT上终止?

script1.sh:

#!/bin/bash ./script2.sh echo after-script

script2.sh:

#!/bin/bash function handler { exit 130 } trap handler SIGINT while true; do true; done

当我从terminal启动script1.sh,然后使用Ctrl + C向其进程组发送SIGINT时,信号被script2.sh捕获,当script2.sh终止时,script1.sh打印“after-script”。 不过,我希望script1.sh在调用script2.sh的行之后立即终止。 为什么在这个例子中不是这种情况?

补充说明(编辑):

是否有系统调用获取正在运行的进程的uid / gid?

在Python中检测64位操作系统(Windows)

如何从.NET应用程序启动`powercfg.exe -energy`?

fork()的function

从32位wix脚本注册64位com组件

由于script1.sh和script2.sh在同一个进程组中,因此在命令行上按Ctrl + C时,SIGINT将发送到两个脚本。 这就是为什么当script2.sh退出时,我不希望script1.sh继续。

当script2.sh中的“trap handler SIGINT”行被注释掉时,script2.sh会在script2.sh存在后立即退出。 我想知道为什么它的行为有所不同,因为script2.sh然后生成相同的退出代码(130)。

如何将字节数组发送到C ++中的另一个进程

我可以等待一个不是当前shellterminal的subprocess的进程终止吗?

debuggingLinux进程挂起问题的实用程序?

一个长整型投射到void *

想学习大会,困惑从哪里开始

新答案:

这个问题比我原先怀疑的要有趣得多。 答案基本上是在这里给出的:

发送给包含子项的perl脚本时,SIGINT(^ C)会发生什么情况?

这里有相关的珍闻。 我意识到你不使用Perl,但我认为Bash使用C的约定。

对于信号而言,Perl的内置系统函数就像标准C库中的C系统(3)函数一样工作。 如果你正在使用Perl的system()版本或者管道打开或反引号,那么父 – 一个调用系统而不是它所调用的那个 – 会在孩子运行时忽略任何SIGINT和SIGQUIT。

这个解释是我见过的关于可以做出的各种选择的最好的解释 。 它也说Bash是WCE的方法。 也就是说,当一个父进程收到SIGINT时,它会等到它的子进程返回。 如果该进程处理从SIGINT退出,它也退出与SIGINT。 如果孩子以任何其他方式退出,则忽略SIGINT。

调用shell还可以判断被调用的程序是否在SIGINT上退出,以及是否忽略了SIGINT(或用于其他目的)。 正如在WUE的方式,壳等待孩子完成。 它计算出程序是否以SIGINT结束,如果是,则停止脚本。 如果该程序做了其他任何退出,脚本将继续。 我将为本文的其余部分打电话做“WCE”(“等待合作退出”)的方式。

我在Bash手册页找不到对此的引用,但我会继续查看信息文档。 但我99%相信这是正确的答案。

老答案:

来自Bash脚本命令的非零退出状态不会终止程序。 如果你做一个echo $? 在./script2.sh之后它将显示130.你可以通过使用set -e来终止脚本。

$ help set ... -e Exit immediately if a command exits with a non-zero status.

@ seanmcl的更新回答的第二部分是正确的,并且http://www.cons.org/cracauer/sigint.html的链接一个非常好的通过仔细阅读。

从这个链接中, 即使你查到你的系统的数值 , 你也不能通过一个具有特殊数值的退出(3)来“伪造”正确的退出状态 。 实际上,这就是@Hermann Speiche的script2.sh中的尝试。

一个答案是修改script2.sh中的函数处理程序,如下所示:

function handler { # ... do stuff ... trap INT kill -2 $$ }

这有效地消除了信号处理程序,并“重新引发”了SIGINT,导致bash进程退出显示相应的标志,使得其父进程正确处理最初发送给它的SIGINT。 这样,使用set -e或任何其他黑客实际上是不需要的。

还值得一提的是,如果你发送一个SIGINT(不符合“如何成为一个正确的程序”在上面的链接,例如它退出一个正常的返回代码)的行为不正确的可执行文件,单向解决这个问题的方法是使用如下脚本来封装对该进程的调用

#!/bin/bash function handler { trap INT kill -2 $$ } trap handler INT badprocess "$@"

原因是你的script1.sh不会终止是script2.sh在一个子shell中运行。 要使前脚本退出,您可以按照phs和seanmcl的建议设置-e ,或者强制script2.sh在同一个shell中运行:

. ./script2.sh

在你的第一个脚本。 如果您在执行脚本之前先set -x ,那么您正在观察的内容会很明显。 help set讲述:

-x Print commands and their arguments as they are executed.

您也可以让第二个脚本通过SIGHUP或其他安全可用的信号(如父脚本可能考虑或陷入的SIGQUIT)发送终止信号(发送SIGINT不起作用)。

script1.sh:

#!/bin/bash trap 'exit 0' SIQUIT ## We Could also just accept SIGHUP if we like without traps but that sends a message to the screen. ./script2.sh ## or "bash script.sh" or "( . ./script.sh; ) which would run it on another process echo after-script

script2.sh:

#!/bin/bash SLEEPPID='' PID=$BASHPID read PPID_ < <(exec ps -p "$PID" -o "$ppid=") function handler { [[ -n $SLEEPPID ]] && kill -s SIGTERM "$SLEEPPID" &>/dev/null kill -s SIGQUIT "$PPID_" exit 130 } trap handler SIGINT # better do some sleeping: for (( ;; )); do [[ -n $SLEEPPID ]] && kill -s 0 "$SLEEPPID" &>/dev/null || { sleep 20 & SLEEPPID=$! } wait done

你脚本中原来的最后一行也可以像这样,取决于你的脚本实现。

./script2.sh || exit ...

要么

./script2.sh [[ $? -eq 130 ]] && exit ...

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐