wc -l
を使用して、コマンドの出力の行をカウントしています。これは、入力がパイプされているためです。
commad | wc -l
これは正常に機能しますが、command
が重い計算を行っている場合、これは非常に遅くなります。 「これまでにパイプされた」行の数を表示する代替はありますか?
このようなことは、次のようなアイテムごとの計算を行うときに特に役立ちます。
cat something | xargs -L1 heavy-per-line-computation | wc -l
これを手動で行う方法の1つは、出力をファイル(command > file
)にパイプし、定期的にcat file | wc -l
を実行することです。しかし、1つのコマンド(無駄なI/Oを回避するためにファイルにリダイレクトされません)が目的です。
awk '{print NR}'
このコマンドは、検出された行ごとに新しい番号を出力します。最後の行が完了すると、最後の番号がwc -l
の発言と一致します。最終行が incomplete の場合、awk
はそれを数える可能性があります(私のKubuntuではGNU awk
はそうです)が、wc -l
は(実際には改行を数えるため)しないので、不一致がある可能性があります。
もう1つの相違点は、入力が完全に空の場合です。wc -l
は0
を出力し、awk
は何も出力しません。印刷するには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
を検討してください。
Rubyを使用したソリューションを次に示します。
count_lines
は(stderr
を介して)最大0.5秒ごとに、これまでに受信した行の数と、最後の合計数(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"
pv
(パイプビュー)を探していると思います。
seq 100000000000 | pv -l | wc -l
ほとんどの端末はCR (\r)
を「列1に移動」と見なします。これにより、以前の出力を上書きし続けることができます。
これは、標準入力から読み取るスクリプトdwc
です(tail -f
ファイルから、または出力プロセス置換から)。スクリプトにはサンプルテストベッドがあります。
-l
オプション。デフォルトでは、入力行番号を端末の現在の行に6桁の数字として出力します。 -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