使用 sleep 和 wait -n 在 bash 中实现简单超时,是否存在竞争条件?

Using sleep and wait -n to implement simple timeout in bash, race condition or not?

如果我在 bash 脚本中这样做:

sleep 10 &
sleep_pid=$!
some_command &
wait -n
cmd_pid=$!

if kill -0 $sleep_pid 2> /dev/null; then
    # all ok
    kill $sleep_pid
else
    # some_command hung
    ...code to log diagnostics and then kill -9 $cmd_pid...
fi

其中 some_command 应该很快但可能会由于罕见的错误而挂起。

那么是否存在 some_command 可以在 "wait -n" 开始之前完成并清理的风险,所以只有等待睡眠?还是一个命令后的 '&' 保证 shell 在处理下一行输入之前不会对其调用 waitpid()?

它在交互式 shell 中工作。如果你这样做:

sleep 10 &
sleep 0 &
wait -n

然后 "wait -n" returns 马上,即使您在 运行 之前等待几秒钟。但我不确定非交互式 shells 是否可以信任它?

编辑: 澄清诊断需求 + 一些语法。

我相信你可以使用超时命令来做到这一点。
http://man7.org/linux/man-pages/man1/timeout.1.html

timeout 10s command_to_run

可以查看timeout命令的退出状态,了解是否超时。

timeout 2s sleep 10

if [[ $? -gt 0 ]]; then
  echo "it timed out"
else
  echo "It was successful"
fi

通过使用 $! 变量,我们避免依赖交互式作业控制功能。试试这个:

...long executing command... &
pid_long=$!

sleep 3 &
pid_sleep=$!

wait -n
kill -KILL $pid_long

这里的问题是PID回收。不过不太可能在 3 秒内发生。

如果命令早于睡眠结束(并且其 PID 尚未回收到新进程)kill 会产生错误消息;我们可以将其通过管道传输到 /dev/null.

我们可能还应该 kill 睡眠,以防 是一个挥之不去的人。

正如@CharlesDuffy 在评论中指出的那样,答案是否定的,不存在种族(前提是 运行 在 non-interactive shell 中)。

也没有必要(在 non-interactive shells 中)确保在命令之后直接等待,因为 non-interactive shells 不需要自动收割 children.

但我想应该将其包装在 sub-shell 中,这样 "wait -n" 就不会 return 由于之前启动的一些不相关的后台作业而提前 return。