我用来wc -l
计算命令输出中的行数,因为输入通过管道传输到它。
commad | wc -l
这工作得很好,但如果command
正在进行一些繁重的计算,这会很慢。是否有其他方法可以显示“到目前为止已通过管道传输”的行数?
当我进行某种逐项计算时,这样的事情特别有用,例如
cat something | xargs -L1 heavy-per-line-computation | wc -l
我可以手动执行此操作的一种方法是将输出通过管道传输到文件 ( command > file
) 并定期cat file | wc -l
对其进行处理。但我所追求的是一个命令(它不会重定向到文件,以避免浪费 I/O)。
答案1
awk '{print NR}'
此命令为遇到的每一行打印一个新编号。如果最后一行完整,那么最后一个数字将与所说的一致wc -l
。如果最后一行是不完整的然后awk
可能会计算它(在我的 Kubuntu GNU 中awk
)但wc -l
不会(因为它确实计算换行符);所以可能会有差异。
另一个差异是如果输入完全为空:wc -l
will print 0
,我们的awk
will 不打印任何内容。要使其打印,0
请使用以下变体:
awk '{print NR} END {if (NR==0) print NR}'
或者您可能希望每个新数字都覆盖控制台同一行中的旧数字。然后这个:
awk '{printf "\r%s",NR} END {print "\r"NR}'
例子:yes | head -n 76543 | awk '{printf "\r%s",NR} END {print "\r"NR}'
请注意,该命令消耗其输入(tee
可能很方便)。出于监控目的,您可能对以下内容感兴趣:
awk '{print NR OFS $0}'
其中(默认OFS
为空格)几乎就像cat -n
(如果您cat
支持-n
)。
pv -l
计算行数并且可以在管道内使用。例子:
for i in 1 2 3 4 5; do date; sleep 1; done | pv -l | wc -l
考虑pv -lb
相当小的输出。
答案2
这是使用 Ruby 的解决方案。
count_lines
stderr
最多每半秒打印一次(通过)迄今为止收到的行数,并在最后打印总行数(通过stdout
)。
read -d '' make_lines <<'EOF'
STDOUT.sync = true
[0.2, 0.1, 0.5, 0.1, 0.6, 0.1, 0.3, 0.1, 0.3, 0.01, 0.01].each do |t|
puts
sleep t
end
EOF
read -d '' count_lines <<'EOF'
lines = 0
t = 0
while gets do
lines += 1
now = Time.now.to_f
if now - t > 0.5
warn lines
t = now
end
end
puts lines
EOF
ruby -e "$make_lines" | ruby -e "$count_lines"
答案3
我认为您正在寻找pv
(管道视图):
seq 100000000000 | pv -l | wc -l
答案4
大多数终端都是CR (\r)
“移至第 1 列”。这允许您继续覆盖以前的输出。
dwc
这是一个将从标准输入(可以是tail -f
文件或输出进程替换)读取的脚本。脚本中有一个示例测试台。
这需要一个-l
选择。默认情况下,将输入行号打印到终端中的当前行,为六位数字。使用 时-l
,它还会打印收到的最后一行的前 60 个字符,并清除以前的任何文本。当它看到 EOF 时,它会发出换行符,因此提示出现在最后一个输出的下方。
#! /bin/bash
#.. dwc [-l]
AWK_SHORT='
BEGIN { Fmt = "\r%6d "; }
{ printf (Fmt, NR); }
END { printf ("\n"); }
'
AWK_LONG='
BEGIN { Fmt = "\r%6d %.60s"; Clr = sprintf ("%60s", ""); }
{ printf (Fmt, NR, $0 Clr); }
END { printf ("\n"); }
'
if [[ "${1}" = "-l" ]]; then
awk "${AWK_LONG}"
else
awk "${AWK_SHORT}"
fi
exit
#.. Test method.
man ls | head -n 40 |
while IFS='' read X; do
printf '%s\n' "${X}"; sleep 0.75
done |
tee >( ./dwc -l ) > foo.txt