为什么使用管道时 `timeout` 命令无法生效?

9
以下命令行调用timeout(没有意义,只是为了测试)未按预期工作。它等待10秒钟,但在3秒钟后无法停止命令的工作。为什么?
timeout 3 ls | sleep 10

你到底期望什么? - FrankieTheKneeMan
@FrankieTheKneeMan 我原本以为 timeout 会执行 ls | sleep 10。因为 ls | sleep 10 至少需要 10 秒钟,所以 timeout 应该会停止它。但是 timeout 没有停止。 - John Threepwood
4个回答

23

你的命令是在运行timeout 3 ls并将其输出导入到sleep 10中。因此,sleep命令不受timeout的控制,总是会休眠10秒。

以下类似的命令会产生期望的效果。

timeout 3 bash -c "ls | sleep 10"

1
现在我能看到我的错误了。很好的解决方法。非常感谢你(再次),你真的帮了我很多。 - John Threepwood
没问题,约翰。很高兴我能帮到你 :) - Shawn Chin
似乎在流上使用grep时不够用:tail -f file | timeout 20s bash -c 'grep "a" | sort | uniq' 没有输出任何内容。 - Ulysse BN

2
“ls”命令不应该花费3秒钟才能运行。我认为发生的情况是你在说(1)在3秒后超时ls(再次,这并没有发生,因为ls不应该花费接近3秒钟的时间运行),然后(2)将结果管道传递到sleep 10中,它不需要比你给它的数字更多的参数。因此,ls发生了,超时没有关系,bash休眠10秒钟。

4
在文件数量较大的目录中,运行 ls 命令可能需要很长时间。 - jordanm
1
没错,你说得对。在那个答案中我做了一些不应该做的假设,感谢你的见解。 - mjgpy3

2

我知道实现你想要的效果的唯一方法是将管道命令放入单独的文件中:

cat > script
ls | sleep 10
^D

timeout 3 sh script

1
你可以使用进程替换来内联执行并避免临时文件 -- timeout 3 sh <(echo "ls | sleep 10") - Shawn Chin

1

只需在管道的最后一个命令上设置超时即可:

# Exits after 3 seconds with code 124
ls | timeout 3 sleep 10

# Exits after 1 second with code 0
ls | timeout 3 sleep 1

持续时间为0会禁用关联的超时。请注意,实际超时持续时间取决于系统条件,在指定亚秒超时时应特别考虑。退出状态:
  • 如果COMMAND超时,则为124
  • 如果'timeout'本身失败,则为125
  • 如果找到COMMAND但无法调用,则为126
  • 如果找不到COMMAND,则为127
  • 如果将KILL(9)信号(128+9)发送给COMMAND,则为137
  • 否则为COMMAND的退出状态
- ShpielMeister

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接