gfr*_*gon 35 bash process stdout
在 bash 脚本中,我想逐行捕获长命令行的标准输出,以便在初始命令仍在运行时对其进行分析和报告。这是我能想象的复杂方法:
# Start long command in a separated process and redirect stdout to temp file
longcommand > /tmp/tmp$$.out &
#loop until process completes
ps cax | grep longcommand > /dev/null
while [ $? -eq 0 ]
do
#capture the last lines in temp file and determine if there is new content to analyse
tail /tmp/tmp$$.out
# ...
sleep 1 s # sleep in order not to clog cpu
ps cax | grep longcommand > /dev/null
done
Run Code Online (Sandbox Code Playgroud)
我想知道是否有更简单的方法。
编辑:
为了澄清我的问题,我将添加这个。在longcommand
由线显示其状态行每秒一次。我想在longcommand
完成之前捕获输出。
这样,longcommand
如果它没有提供我期望的结果,我可能会杀死它。
我试过了:
longcommand |
while IFS= read -r line
do
whatever "$line"
done
Run Code Online (Sandbox Code Playgroud)
但是whatever
(eg echo
) 仅在longcommand
完成后执行。
Gra*_*eme 44
只需将命令通过管道传输到while
循环中即可。这有许多细微差别,但基本上(在bash
或任何 POSIX shell 中):
longcommand |
while IFS= read -r line
do
whatever "$line"
done
Run Code Online (Sandbox Code Playgroud)
另一个主要问题(除了IFS
下面的内容)是当您尝试在循环完成后从内部使用变量时。这是因为循环实际上是在一个子 shell(只是另一个 shell 进程)中执行的,你不能从中访问变量(当循环执行时它也完成了,此时变量完全消失了。为了解决这个问题,你可以做:
longcommand | {
while IFS= read -r line
do
whatever "$line"
lastline="$line"
done
# This won't work without the braces.
echo "The last line was: $lastline"
}
Run Code Online (Sandbox Code Playgroud)
设置的Hauke的例子lastpipe
中bash
是另一种解决方案。
为确保您正在处理“发生时”命令的输出,您可以使用stdbuf
将进程设置stdout
为行缓冲。
stdbuf -oL longcommand |
while IFS= read -r line
do
whatever "$line"
done
Run Code Online (Sandbox Code Playgroud)
这将配置进程一次将一行写入管道,而不是在内部将其输出缓冲到块中。请注意,程序可以在内部自行更改此设置。使用unbuffer
(的部分expect
)或可以实现类似的效果script
。
stdbuf
在 GNU 和 FreeBSD 系统上可用,它只影响stdio
缓冲并且只适用于动态链接的非 setuid、非 setgid 应用程序(因为它使用 LD_PRELOAD 技巧)。
#! /bin/bash
set +m # disable job control in order to allow lastpipe
shopt -s lastpipe
longcommand |
while IFS= read -r line; do lines[i]="$line"; ((i++)); done
echo "${lines[1]}" # second line
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
88098 次 |
最近记录: |