在shell脚本中实现无限等待
这听起来可能很琐碎,但我很确定这个问题没有被问到,或者至少我找不到 我正在寻找一种方法,用shell脚本构建一个无限等待(不一定是一个循环),这样它就永远等待,并且可以被杀死(或者从技术上讲,接收一个在shell脚本中实现无限等待,shell,unix,Shell,Unix,这听起来可能很琐碎,但我很确定这个问题没有被问到,或者至少我找不到 我正在寻找一种方法,用shell脚本构建一个无限等待(不一定是一个循环),这样它就永远等待,并且可以被杀死(或者从技术上讲,接收一个SIGTERM)。以下是已知的可能构造和反对它们的参数: 为true时;做睡眠1;已完成这几乎可以完成,但由于睡眠是一个外部命令,因此当我向正在运行的脚本发送SIGTERM时,它必须先等待睡眠完成,然后再处理信号。将sleep 1更改为类似sleep 10的内容,滞后将变得明显。此外,该解决方案每1
SIGTERM
)。以下是已知的可能构造和反对它们的参数:
为true时;做睡眠1;已完成
这几乎可以完成,但由于睡眠
是一个外部命令,因此当我向正在运行的脚本发送SIGTERM
时,它必须先等待睡眠
完成,然后再处理信号。将sleep 1
更改为类似sleep 10
的内容,滞后将变得明显。此外,该解决方案每1秒唤醒一次CPU,这并不理想为true时;一定要读书;完成
当stdin
为tty时,这是完美的read
是一个shell内置项,SIGTERM
立即到达脚本。但是,当stdin
为/dev/null
时,脚本会通过在/dev/null
上永远运行read
来消耗所有CPUmandash
我没有找到这样一个-唯一的阻塞内置是read
和wait
,我不知道如何使用wait
构建一个理想的
答案应该适用于POSIX shell(实际上是dash
),或者不如Bash
附加说明。
第一个例子不能完美工作的情况比我想象的要复杂。使用以下shell脚本:
#!/bin/sh
echo $$
while true; do
sleep 100
done
如果你在另一个tty杀死它,它会立即终止。当你尝试做诱捕时,有趣的事情就开始了。使用此脚本:
#!/bin/sh
at_term() {
echo 'Terminated.'
exit 0
}
trap at_term TERM
echo $$
while true; do
sleep 20
done
发生的情况在示例1中有确切描述。这在bash、dash和zsh中发生。在这种情况下,我正在寻找一个“完美的”无限外观构造。发送到进程的SIGTERM由内核传递到进程,无论进程是否处于睡眠状态 尝试尝试一下,也许像这样(bash示例)
您的第二个选项有什么问题,但强制它从
stdin
读取?(需要bash
)
您可以使用命名管道进行读取:
mkfifo /tmp/mypipe
#or mknode /tmp/mypipe p
如果以后要向管道发送不同的任意“信号”,可以将读取与case语句结合使用,以采取适当的操作(甚至是有用的操作)
读取信号时;做
大写“$SIGNAL”
*退出*)中断;;
*)echo“信号$signal不受支持”>/dev/stderr;;
以撒
完成
如果您有接受浮点秒的GNU coreutils,您可以尝试:
sleep inf
这将一直阻止,直到64位时间戳环绕。这里有一个没有循环的解决方案:
#!/usr/local/bin/dash
echo $$
# -$$: kill process group (parent and children)
#trap 'trap - TERM; kill 0' TERM
#trap 'trap - INT TERM; kill 0' INT TERM
trap 'trap - TERM; kill -s TERM -- -$$' TERM
tail -f /dev/null & wait
exit 0
为什么不使用“永远睡眠”?这是为了永久阻止。当我发送一个
SIGTERM
到一个dash
循环执行sleep 100
时,它会立即退出。你需要这个做什么?如果进程应该持续,但什么也不做,它可能会给自己发送一个SIGSTOP
,因此,有理由怀疑它可能并不总是可用的。如果有人能提供一些关于/dev/stdin:)的文档,那就太好了。当stdin被重定向到/dev/null时,它会崩溃。把它放在a.sh中,运行bash a.sh
,然后看到CPU被吃掉了……是的,这个几乎是完美的。我会看看是否有人能想出更简单的方法,或者我会接受……接受你的答案:)这在任何情况下都是通用的。谢谢你的解决方案!就我个人而言,我认为它比使用阅读
更优雅,而且它工作得非常完美!你的剧本很神奇!这是唯一一个做我想做的(对信号15的响应)。你能详细解释一下吗?那你为什么一个接一个地重复这个陷阱呢?在trap中编写的所有内容对我来说都不清楚,为什么&tail之后,为什么还要等待?@MohammedNoureldintrap-TERM
部分删除了脚本中现有的trap处理程序,这样就不会再次捕获相同的信号。kill-s TERM--$$
部分将SIGTERM
发送到同一进程组中的所有进程。有效地执行所有子进程和子进程(包括脚本本身)。也就是说,就kill
而言,负PID是PGID,但我们需要额外的--
以避免与命令开关混淆。由于SIGTERM
处理程序已被删除,当接收到第二个SIGTERM
信号(它在旧处理程序中发送)时,脚本将终止。如果您没有inf
(例如在alpine/sh上),您可以始终将其放入无限循环中。无论哪种方式,这都是有效的。如果只有shell脚本(而不是sleep(1)进程)接收到信号,这就不起作用。
mkfifo /tmp/mypipe
#or mknode /tmp/mypipe p
while read SIGNAL; do
case "$SIGNAL" in
*EXIT*)break;;
*)echo "signal $SIGNAL is unsupported" >/dev/stderr;;
esac
done < /tmp/mypipe
#!/bin/sh
at_term() {
echo 'Terminated.'
exit 0
}
trap at_term TERM
echo $$
while true; do
sleep 20 &
wait $!
done
sleep inf
#!/usr/local/bin/dash
echo $$
# -$$: kill process group (parent and children)
#trap 'trap - TERM; kill 0' TERM
#trap 'trap - INT TERM; kill 0' INT TERM
trap 'trap - TERM; kill -s TERM -- -$$' TERM
tail -f /dev/null & wait
exit 0