带有管道输入的 Bash 超时



有一个命令(比如$run_command),超时后必须将其终止。解决方案非常简单 - 我可以只使用来自 coreutils 的超时或来自其他堆栈溢出主题的 timeout3。但是我的命令从 untar 管道 smth 收到它的 stdin,就像这样

tar -xO -f "$1" | /usr/bin/time -f "%e" --output=$time_output -- $run_command

其中$run命令是我的命令,执行时间也被测量(使用时间实用程序)。

因此,问题是避免在超时实用程序中包含未延迟时间的最佳方法是什么?

在非常简单的形式中,您可以像这样终止调用脚本:

#!/bin/bash
( sleep $timeout_period && kill $$ ) &
tar -xO -f "$1" | ...

当然,这只是一个例子;您需要提供一些保险,即 $$ 在运行时仍然是相同的脚本kill

这当然会杀死整个脚本,包括time(如果脚本被杀死,它将是 $timeout_period)。

更新#1

使用临时文件的示例。

tmpfile=$(/usr/bin/mktemp /tmp/temp.XXXXX)
tar -xO -f "$1" > $tmpfile
trap "rm -f $tmpfile" 0 1 2 3 15
/usr/bin/time -f "%e" --output=$time_output -- $run_command < $tmpfile

请注意,由于文件系统的速度/性能,这仍然容易出错。

更新#2

除了免除tar时间外,这还添加了超时功能:

(
  tmpfile=$(/usr/bin/mktemp /tmp/temp.XXXXX)
  tar -xO -f "$1" > $tmpfile
  trap "rm -f $tmpfile" 0 1 2 3 15
  /usr/bin/time -f "%e" --output=$time_output -- $run_command < $tmpfile
) &
pid=$!
( sleep $timeout_period && kill $pid ) &
wait %1

在第一个脚本段中也存在相同的潜在问题;您需要提供保险,证明 $$ 仍然是您在杀死它之前所认为的。 此外,信号将发送到 shell 包装器,而不是直接发送到您的命令。 您必须测试信号是否按预期传递到您的命令。

另请注意,这为超时/终止提供了背景。 "等待"告诉脚本等到第一个后台进程完成,所以你的命令要么自己完成,要么它被超时杀死......然后脚本继续wait之后的任何内容。 如果命令自行完成,则会遇到$pid被回收用于另一个进程的潜在问题。 解决这个问题留给读者作为练习。 :-)

我认为您在此示例中查找的是临时文件,而不是管道。在大多数情况下,您希望并行执行管道。在您的情况下(性能分析),以及前面的命令在执行后面的命令之前应该成功时,顺序操作是可取的。我建议使用mktemp来实现此效果。在这个例子中,我不知道有什么方法可以通过进程替换或mkfifo来使用 FIFO,因为$run_command总是依赖于 tar 的输出。

相关内容

  • 没有找到相关文章

最新更新