如何从一个从管道中读取的程序获得持续更新的输出?例如,我们假设此程序是wc
的一个版本:
$ ls | running_wc
所以我想要立即输出,例如
0 0 0
然后每次收到新的输出行时,它都会再次更新,例如
1 2 12
2 4 24
etc.
当然我的命令并不是ls
,它是一个慢慢输出数据的过程......我真的喜欢动态地让它计算匹配和非匹配,以及将此信息汇总到一行,例如
$ my_process | count_matches error
这将不断更新具有匹配和非匹配计数的单行输出,例如:
$ my_process | count_matches error
0 5
然后它可能看起来像是这样,因为它找到了2个匹配和10个不匹配的行。
$ my_process | count_matches error
2 10
答案 0 :(得分:3)
dd
会在收到SIGUSR1
信号后打印出统计信息,但wc
和grep
都不会。你需要或多或少地重新实现它们。
count_matches() {
local pattern=$1
local matches=0 nonmatches=0
local line
while IFS= read -r line; do
if [[ $line == *$pattern* ]]; then ((++matches)); else ((++nonmatches)); fi
printf '\r%s %s' "$matches" "$nonmatches"
done
printf '\n'
}
每次打印回车\r
会导致打印输出相互覆盖。
在管道中使用时,大多数程序将从行缓冲切换到完全缓冲。您的慢速运行程序应在每行后刷新其输出,以确保结果立即可用。或者,如果您无法修改它,您通常可以使用stdbuf -oL
强制使用C stdio的程序行缓冲区标准输出。
stdbuf -oL my_process | count_matches error
答案 1 :(得分:1)
使用awk。首先,我们创建“my_process
”:
$ for i in {1..10} ; do echo $i ; sleep 1 ; done # slowly prints lines
比赛计数器:
$ awk 'BEGIN {
print "match","miss" # print header
m=0 # reset match count
}
{
if($1~/(3|6)/) # match is a 3 or 6 (for this output)
m++ # increment match count
print m,NR-m # for each record output match / miss counts
}'
运行它:
$ for i in {1..10} ; do echo $i ; sleep 1 ; done | awk 'BEGIN{print "match","miss";m=0}{if($1~/(3|6)/)m++;print m,NR-m}'
match miss
0 1
0 2
1 2
1 3
1 4
2 4
2 5
2 6
2 7
2 8