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 次 |
| 最近记录: |