这可能听起来微不足道,但我很确定这个问题没有被问到,或者至less我找不到。
我正在寻找一种方法来构build一个无限的等待 (不一定是循环)与shell脚本,以便它永远等待,可以被杀害 (或技术上,接收SIGTERM
)。 以下是已知的可能的结构和论点:
while true; do sleep 1; done
while true; do sleep 1; done
这几乎得到它,但由于sleep
是一个外部命令,当我发送一个SIGTERM
到正在运行的脚本,它必须等待sleep
完成,然后处理信号。 把sleep 1
改变成像sleep 10
,滞后将是显而易见的。 此外,解决scheme每1秒就会唤醒CPU,这并不理想。 while true; do read; done
当stdin
是tty时,这是完美的。 read
是一个shell内部和SIGTERM
即刻到达脚本。 但是,当stdin
是/dev/null
,脚本通过无可奈何地在/dev/null
上永远运行read
吞噬所有的CPU。 因此需要一个永远等待的shell内build构造 。 通过man dash
略读,我没有find这样一个 – 唯一的阻止内置的read
和wait
,我不知道如何构build一个理想的使用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中。 在这种情况下,我正在寻求一个“完美的”无限的外观构造。
你可以使用一个命名管道来读取:
mkfifo /tmp/mypipe #or mknode /tmp/mypipe p
如果您稍后想要向管道发送不同的任意“信号”,则可以将读取与case语句结合使用以采取适当的操作(即使是有用的操作)
while read SIGNAL; do case "$SIGNAL" in *EXIT*)break;; *)echo "signal $SIGNAL is unsupported" >/dev/stderr;; esac done < /tmp/mypipe
如果你有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
你的第二个选项有什么问题,但强制它从stdin
读取? (需要bash
)
while true; do read done < /dev/stdin
从man bash
Bash处理几个文件名,特别是当它们用于重定向时,如下表所述:
/dev/stdin File descriptor 0 is duplicated.
#!/bin/sh at_term() { echo 'Terminated.' exit 0 } trap at_term TERM echo $$ while true; do sleep 20 & wait $! done
发送到进程的SIGTERM由内核传递给进程,无论它是否正在休眠。
尝试尝试,也许这样(bash例子)
sleep 20 & kill $! && fg