GNU/Linux >> Linux の 問題 >  >> Linux

printf ビルトインを使用して現在の時間をミリ秒またはナノ秒で出力する

bash v5 と $EPOCHREALTIME

  • EPOCHREALTIME マイクロ秒の粒度を持つ浮動小数点値

  • EPOCHSECONDS Unix エポックからの秒数

正しい方法

簡単に:

IFS=. read ESEC NSEC <<<$EPOCHREALTIME
printf '%(%F:%T)T.%06.0f\n' $ESEC $NSEC

1. $EPOCHREALTIME について

気をつけてください:

    EPOCHREALTIME
         Each time this parameter is referenced, it expands to the number
         of seconds since the Unix Epoch  (see  time(3))  as  a  floating
         point  value  with  micro-second  granularity.

したがって、同じ行で同じ変数を 2 回要求すると、次のようになります。

echo $EPOCHREALTIME...  $EPOCHREALTIME 
1572000683.886830... 1572000683.886840

またはより明確に:

printf "%s\n" ${EPOCHREALTIME#*.} ${EPOCHREALTIME#*.}
761893
761925

echo $((  -10#${EPOCHREALTIME#*.} + 10#${EPOCHREALTIME#*.} ))
37

私のラズベリーパイでも同じです:

printf "%s\n" ${EPOCHREALTIME#*.} ${EPOCHREALTIME#*.}
801459
801694

echo $((  -10#${EPOCHREALTIME#*.} + 10#${EPOCHREALTIME#*.} ))
246

したがって、整数部分と小数部分を構築するためのこの 2 つの時間を照会すると、プロセスが分離される可能性があります:(同じ行で最初に $ EPOCHREALTIME にアクセスする 与えることができます:NNN1.999995 、次:NNN2.000002 .結果は次のようになります:NNN1.000002 1000000 マイクロ秒の誤差)

2.警告! $EPOCHSECONDS の混在について および $EPOCHREALTIME

両方を一緒に使用すると、最初に述べたバグにつながるだけではありません!

$EPOCHSECONDS time() への呼び出しを使用 $EPOCHREALTIME の間、常に更新されるわけではありません gettimeofday() への呼び出しを使用 !したがって、結果は大きく異なる可能性があります:

time() と gettimeofday() に対するこの回答が異なる秒を返すことを発見しました よく説明してください。

ホストで試してみると:

epochVariableDiff () {
    local errcnt=0 lasterrcnt v1 v2 v3 us vals line
    while ((errcnt==0)) || ((errcnt>lasterrcnt)); do
        lasterrcnt=$errcnt
        printf -v vals '%(%s)T %s %s' -1 $EPOCHSECONDS $EPOCHREALTIME
        IFS=$' .' read v1 v2 v3 us <<<"$vals"
        [ "$v1" = "$v2" ] && [ "$v2" = "$v3" ] || ((errcnt++))
        [ $errcnt -eq 1 ] && echo "$line"
        printf -v line '%3d %s - %s - %s . %s' $errcnt $v1 $v2 $v3 $us
        printf "%s\r" "$line"
        ((errcnt)) && echo "$line"
        read -t ${1:-.0002}
    done
}

(
注:read -t を使用します sleep の代わりに 、なぜなら sleep 組み込みではありません
注 2:関数の引数をいじって、読み取りタイムアウト (スリープ) の値を変更できます。
)

これにより、何かが台無しになる可能性があります:

$ epochVariableDiff .0002
  0 1586851573 - 1586851573 - 1586851573 . 999894
  1 1586851573 - 1586851573 - 1586851574 . 000277
  2 1586851573 - 1586851573 - 1586851574 . 000686
  3 1586851573 - 1586851573 - 1586851574 . 001087
  4 1586851573 - 1586851573 - 1586851574 . 001502
  5 1586851573 - 1586851573 - 1586851574 . 001910
  6 1586851573 - 1586851573 - 1586851574 . 002309
  7 1586851573 - 1586851573 - 1586851574 . 002701
  8 1586851573 - 1586851573 - 1586851574 . 003108
  9 1586851573 - 1586851573 - 1586851574 . 003495
 10 1586851573 - 1586851573 - 1586851574 . 003899
 11 1586851573 - 1586851573 - 1586851574 . 004400
 12 1586851573 - 1586851573 - 1586851574 . 004898
 13 1586851573 - 1586851573 - 1586851574 . 005324
 14 1586851573 - 1586851573 - 1586851574 . 005720
 15 1586851573 - 1586851573 - 1586851574 . 006113
 16 1586851573 - 1586851573 - 1586851574 . 006526
 17 1586851573 - 1586851573 - 1586851574 . 006932
 18 1586851573 - 1586851573 - 1586851574 . 007324
 19 1586851573 - 1586851573 - 1586851574 . 007733
 19 1586851574 - 1586851574 - 1586851574 . 008144

$EPOCHREALTIME の整数部分 8000 以上増加する可能性があります $EPOCHSECONDS マイクロ秒前 (私のホスト上で)

注意: これはいくつかのバグに関連しているようです 、異なるホスト間または再起動後の同じホスト間で結果が大きく異なる可能性があります...奇妙なことに、多くの異なるホスト(Intel Core、Intel Xeon、Amd64 ..)でそれらを再現できましたが、raspberry piでは再現できませんでした! ? (同じ Debian bash v5.0.3(1) リリース)、異なるカーネル バージョン。

正解: これはバグではありません。ミキシング time()gettimeofday() はバグです!

したがって、両方を一緒に使用しないでください!!!

3. printf "..%06.0f" について

注:%06.0f を使用します %d の代わりに $NSEC を保証する 10 進数 (float) として解釈されます (変数が 0 で始まる場合、8 進数の解釈を防ぎます) ).

比較:

printf "nn.%06.0f\n" 012345
nn.012345

printf "nn.%06.0f\n" 098765
nn.098765

そして

printf "nn.%d\n" 012345
nn.5349

printf "nn.%d\n" 098765
-bash: printf: 098765: invalid octal number
nn.0

サンプルラン

ちょっとしたテスト:

次の秒まで待ってから、現在の時刻をマイクロ秒で出力

while ! read -t .$((1000000-10#${EPOCHREALTIME#*.})) foo; do
    IFS=. read ESEC NSEC <<< $EPOCHREALTIME
    printf '%(%F:%T)T.%06.0f\n' $ESEC $NSEC
done

Return を押すと、このテストを終了できます

2019-10-25:13:16:46.000444
2019-10-25:13:16:47.000489
2019-10-25:13:16:48.000399
2019-10-25:13:16:49.000383
2019-10-25:13:16:50.000508

Linux
  1. Linuxatコマンドでタスクをスケジュールする

  2. ChronyでNTPを管理する

  3. Linuxサーバー時間をネットワークタイムサーバーと同期する

  1. Arduino YunのOpenwrtのミリ秒単位の日付?

  2. タイムゾーンで開始時間を処理しますか?

  3. printf での色の使用

  1. Linuxで印刷するための3つのヒント

  2. ミリ秒単位の時間を取得するコマンド

  3. Linux で現在の日付と時刻の名前のファイルを作成する方法