例子

例子

有没有一种简单的方法来创建只能持续给定量的墙壁时间的管道?

我希望能够拍摄一段时间内正在写入 STDOUT 的内容(而不是字节或行)的“快照”。就像是

tail -f /var/log/whatever.log | pipe_for_seconds 10 > ./10_second_sample_of_log

我正在使用 BASH,但如果这在其他 shell 中更加容易,我想听听。

答案1

格努核心工具从7.0版本开始有一个timeout命令:

timeout 10 tail -f /var/log/whatever.log 

如果你真的需要一个管道来超时一些稍微不同的过程,然后通过管道进入timeout

tail -f /var/log/whatever.log | timeout 10 cat > ./10_second_sample_of_log

但请注意终止管道的任意部分可能会因缓冲而导致问题,取决于信号和程序行为(这个问题涵盖了相关问题:关闭管道中的缓冲)。它通常会改变退出代码的过程也是如此。

如果您没有(最近的)coreutils,这个简单的超时程序也可以很好地工作 http://www.unixlabplus.com/unix-prog/timeout/timeout.html 或 perl 方法:

tail -f /var/log/whatever.log | perl -n -e 'BEGIN{alarm 10; $|=1}; print;'

(请注意,$|=1关闭输出缓冲,这是为了防止管道中的输出丢失,如上所述。)

(稍微古老)网络管道软件包还有一个timelimit命令(您仍然可以在某些 Linux 系统上找到该命令)。

这个类似的问题还有几个选项:如何为shell脚本引入超时?

答案2

这应该有效:

tail -f /var/log/whatever.log > ten_second_sample & sleep 10 && kill $!

tail在后台并行启动sleep10 秒在那之后 kill $!这是最后启动的后台进程的PID。

答案3

tail -f如果退出太快(例如文件不存在),依靠杀死PID可能不可靠。另一个更通用的解决方案,如果在超时之前完成“终止计时器”,则也会停止使用waitand kill %%%%表示由 bash - using 启动的最近作业&)。

构造将如下所示(其中sleep 2是带有参数等的任何自定义命令,超时设置为 10 秒):

# Your command that may take some (or not) time to execute:
sleep 2 &
# Set a timer that kills the last started job
sleep 10 & wait -n 1; kill %%; wait -n 1

此构造将等待,直到达到超时或自定义命令执行完毕(在这种情况下,总是sleep 2先停止)。然后,命令或超时将分别被终止kill %%。然后,最后一个wait -n 1阻止进一步执行,直到命令或超时实际上被终止(这是可选的,但可能是需要的)。

笔记。正如所要求和预期的那样,早期并行执行的命令不会受到影响。

例子

read一个更实际的示例,从带有超时的命名管道读取一行,但不能使用超时标志:

# Custom bash function to set timeout in seconds for the most recently started job (parallel execution).
timeout() { sleep $1 & wait -n 1; kill %%; wait -n 1 }

# Example 1:
mkfifo /tmp/test
read ln </tmp/test &
timeout 10

因为没有写入任何内容,/tmp/test10秒后就会超时。为了表明即使命令立即终止它也会停止终止计时器:

# Example 2:
mkfifo /tmp/test
echo "Hello" >/tmp/test &
ln="$(read ln </tmp/test && echo -e "$ln" & timeout 10)"
echo "Line was read: $ln"

请注意命名管道的实际使用。因为read ln是在子shell中执行的,所以无法在(父)脚本中访问它。因此,该行被打印以echo将其存储在(不同的)变量中ln

相关内容