私は、標準入力の各行の前に標準入力を生成するのにかかる時間に関する情報を追加するスクリプトが必要です。デフォルトでは入力用:
foo
bar
baz
持ちたい
0 foo
10 bar
5 baz
10はfooの印刷とバーの印刷にかかる10秒です。 5と同様に、バーを印刷してからbazを印刷するのに5秒かかります。
ts
タイムスタンプを表示できるユーティリティがあることがわかります。https://github.com/paypal/gnomonしかし、これを行うためにJavaScriptを使用したくありません。
標準ツールはありますか?それとも、これにはawkを使用する必要がありますか?
答え1
出力を生成するスクリプトがあるとしますgenerate
。次に、各行を作成するのにかかる時間(秒単位)を表示します。
$ generate | ( t0=$(date +%s); while read -r line; do t1=$(date +%s); echo " $((t1-t0)) $line"; t0=$t1; done )
2 foo
0 foo
5 foo
3 foo
複数行にまたがる同じコマンドは次のとおりです。
generate | ( t0=$(date +%s)
while read -r line
do
t1=$(date +%s)
echo " $((t1-t0)) $line"
t0=$t1
done
)
または、便宜上、次のコードを含むシェル関数を定義できます。
timer() { t0=$(date +%s); while read -r line; do t1=$(date +%s); echo " $((t1-t0)) $line"; t0=$t1; done; }
この機能は次のように使用できます。
$ generate | timer
0 foo
2 foo
4 foo
3 foo
どのように動作しますか?
t0=$(date +%s)
スクリプトが開始された現在の時刻を秒単位でキャプチャします。
while read -r line; do
標準入力でループの読み出しが開始されます。
t1=$(date +%s)
これは、現在行がキャプチャされてからの秒数をキャプチャします。
echo " $((t1-t0)) $line"
現在の行にかかった時間を秒単位で印刷します。
t0=$t1
これにより、
t0
次の行が更新されます。done
これはサイクルの終わりを示します
while
。
答え2
trickle () {
awk 'BEGIN { t = systime(); OFS="\t" }
{ print systime() - t, $0 }
{ t = systime() }'
}
この小さなシェル関数は単にawk
スクリプトをラップします(GNUとGNUと互換性がありますが、awk
BSDmawk -Wi
が不足してBSDと互換性がありません)。最後の出力行以降の秒数を前に付けて、各入力行を出力します。最初の行にはゼロが前に付けられます。awk
systime()
テスト:
$ { echo hello; sleep 2; echo world } | trickle
0 hello
2 world
スクリプトawk
はスタンドアロンで実行することもできます。
$ some_command | awk 'BEGIN{OFS="\t";t=systime()}{print systime()-t,$0;t=systime()}
例えば
$ { echo hello; sleep 2; echo world; } | awk 'BEGIN{OFS="\t";t=systime()}{print systime()-t,$0;t=systime()}'
0 hello
2 world
答え3
素晴らしい、その他のユーティリティ ts
完璧なツールのようです。
開始後秒:
$ seq 5 | pv -qL 1 | ts -s %s
2 1
4 2
6 3
8 4
10 5
またはより正確には:
$ seq 5 | pv -qL 1 | ts -s %.s
1.949228 1
3.933483 2
5.917923 3
7.902231 4
9.886618 5
または、またはzsh
を使用しますksh93
($SECONDS
デフォルトは整数ですが;を使用して浮動小数点にすることもできます。typeset -F
これpdksh
もbash
機能し$SECONDS
ますが、整数に固有のものです)。
$ typeset -F SECONDS=0; seq 5 | pv -qL 1 | while IFS= read -r line; do
printf '%.3f %s\n' "$SECONDS" "$line"; done
1.987 1
3.972 2
5.956 3
7.941 4
9.925 5
行間の秒数
$ seq 5 | pv -qL 1 | ts -i %.s
1.947814 1
1.984442 2
1.984456 3
1.984151 4
1.984195 5
zsh
/ ksh93
:
$ typeset -F SECONDS; seq 5 | pv -qL 1 | while SECONDS=0; IFS= read -r line; do
printf '%.6f %s\n' "$SECONDS" "$line"; done
1.985298 1
1.984322 2
1.984212 3
1.984240 4
1.984441 5
答え4
まず、bash組み込み関数を使用して単純な関数を作成しますSECONDS
。すべての呼び出しでこれをゼロに初期化することに注意してください。
_time() { SECONDS=0; out="$($@)"; echo "[${SECONDS}] ${out:-no output}"; }
次に、この_time
関数を使用してコマンドリスト(コマンドファイルなど)からコマンドを実行します。
while read cmd; do _time $cmd; done < <(echo -e "sleep 5\nsleep 2\nsleep 1")
ここでsleepには出力はありませんが、コマンドは出力できます。これは、この質問に関連するSECONDSの使用を示すためのものです。この例では、次の基本出力を出力しますno output
。
[5] no output
[2] no output
[1] no output