tarファイルを抽出し、1秒あたりに抽出されたファイル数を印刷する次のコマンドには、いくつかの問題があります。
tar -xvf some_tar.tar -C a/directory | awk 'systime() > lasttime { lasttime = systime(); printf "%d files\n", NR; fflush(stdout) }'
tarコマンドが失敗しても、awkコマンドはまだ0を返しますが、これはtarコマンドの失敗を反映していないため、望ましくありません。
この問題をどのように解決できますか?
答え1
pipefail
パイプラインのコマンドが失敗したことを確認するには、このオプションを設定します。 Bashに加えて、ksh、zsh、およびBusybox(少なくとも)もこれをサポートします。このオプションが設定されている場合、パイプの終了状態は、関連コマンドによって返される最も左側のゼロ以外の終了状態です。
$ set -o pipefail
$ (exit 123) | true
$ echo $?
123
あるいは、パイプは条件付きです(「失敗しました」とマークする必要があります)。
set -o pipefail
if false | true; then
echo it succeeded
else
echo it failed
fi
答え2
最新バージョンの1つのアプローチは、bash
コマンドパイプラインを呼び出した後に配列変数の値を確認することです。 Bashのマニュアルページによると:PIPESTATUS
tar|awk
PIPESTATUS
An array variable (see Arrays below) containing a list of exit status
values from the processes in the most-recently-executed foreground
pipeline (which may contain only a single command).
したがって、tarの終了コードはにあり、${PIPESTATUS[0]}
awkの終了コードはにあります${PIPESTATUS[1]}
。
答え3
パイプはまったく使用されません。名前付きパイプを使用してください。
mkfifo p
awk '...' < p &
tar -xvf some_tar.tar -C a/directory > p
echo $?
このawk
コマンドはバックグラウンドで実行され、tar
名前付きパイプへの書き込みが開始されるまでブロックされます。tar
パイプの終わりを終了して閉じると、最後awk
から残りの内容を読み取って終了します。このコマンドは代わりに終了ステータスをecho
報告します。tar
awk
答え4
各入力ラインを呼び出すと、パイプラインの速度が大幅に遅くなると予想されるため、パイプラインのsystime()
出力は1秒あたりのtar抽出ファイル数を正確に反映しません。進行状況インジケータを表示するには、systime()
1000 万行または 100 万入力の入力行ごとに 1 回だけ呼び出すことを検討するか、まったく呼び出すことなく、100 万行または 100 万入力行ごとに印刷することを検討してください。 1秒あたりのファイルをインポートしていますsystime()
。
要求された問題を解決し、呼び出しのオーバーヘッドをほぼ完全に排除するには、次の操作を実行することを検討してくださいsystime()
(GNU awkを時間関数として使用し、最後に読み込んだ行を$0
含めEND
、入力にNULを含めることができます)。
{ tar -xvf some_tar.tar -C a/directory && printf '\0\n'; } |
awk -v n=1000000 '
BEGIN { beg = systime() }
NR%n == 0 { printf "%d files processed\n", NR }
END {
end = systime()
if ( $0 == "\0" ) {
numFiles = NR - 1
exitStatus = 0
}
else {
numFiles = NR
exitStatus = 1
}
printf "%d files per sec\n", numFiles / (end > beg ? end - beg : 1)
exit exitStatus
}
'