各行の前にその行を作成するのにかかる時間を追加します。

各行の前にその行を作成するのにかかる時間を追加します。

私は、標準入力の各行の前に標準入力を生成するのにかかる時間に関する情報を追加するスクリプトが必要です。デフォルトでは入力用:

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と互換性がありますが、awkBSDmawk -Wiが不足してBSDと互換性がありません)。最後の出力行以降の秒数を前に付けて、各入力行を出力します。最初の行にはゼロが前に付けられます。awksystime()

テスト:

$ { 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これpdkshbash機能し$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

関連情報