web-dev-qa-db-ja.com

各行の前に、それを生成するのにかかった時間を付けます

Stdinの各行の前に、生成にかかった時間の情報を付加するスクリプトが必要です。基本的に入力用:

foo
bar
baz

私はを頂きたい

0 foo
10 bar
5 baz

Fooの印刷とバーの印刷の間で10が10秒経過した場合、5の場合と同様に、バーを印刷してからbazを印刷するのに5秒かかりました。

タイムスタンプを表示するユーティリティtsがあり、 https://github.com/Paypal/gnomon について知っていますが、JavaScriptを使用したくないと思います。

そのための標準ツールはありますか、それともawkを使用して処理を行う必要がありますか?

3

出力を生成するスクリプトが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)

    これにより、スクリプトの開始時の現在の時刻がEpoch以降の秒数でキャプチャされます。

  • _while read -r line; do_

    これにより、標準入力から読み取るループが開始されます

  • t1=$(date +%s)

    これは、現在の回線がキャプチャされたEpoch以降の時間を秒単位でキャプチャします。

  • echo " $((t1-t0)) $line"

    これにより、現在の行にかかった時間が秒単位で出力されます。

  • _t0=$t1_

    これにより、次の行の_t0_が更新されます。

  • done

    これは、whileループの終了を示します。

5
John1024
_trickle () {
    awk 'BEGIN { t = systime(); OFS="\t" }
               { print systime() - t, $0 }
               { t = systime()           }'
}
_

この小さなシェル関数は、単にawkスクリプトをラップします(GNU awkと_mawk -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
_
5
Kusalananda

time (注:シェル組み込みではなく、別のバイナリ)を使用して、whileループと組み合わせることができます。各コマンドの実行時間を取得するには:

while read -r line; do
    /usr/bin/time -f "%e %C" $line 2>&1
done

出力例:

0.1 sleep 0.1
0.2 sleep 0.2
1.0 sleep 1

最初からの合計実行時間が必要な場合は、各ステップの実行時間を合計する必要があります。 %e形式の精度は1/100秒であるため、 シェル整数演算 を直接使用することはできません(使用しているシェルによって異なります)。

total=0.0

while read -r line; do
    t=$(/usr/bin/time -f "%e" $line 2>&1)
    total=$(awk "BEGIN{print $total+$t}")
    echo "$total $line"
done

出力例:

0.1 sleep 0.1
0.3 sleep 0.2
1.3 sleep 1
2
sebasth

ええと、 moreutilstsはそのための完璧なツールのようです:

開始から数秒間:

$ 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

$ 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
2