長すぎます。

長すぎます。

シェル:バッシュ。

目標:printfを使用して、タイムスタンプ処理に適した固定時点以降の時間t(ミリ秒)を取得します。

条件:解決策は完全な行テキストテストに合格する必要があります。

さらに、解決策は原子性(はい、そうです!..)でなければならず、軽くなければならず、量子化と丸めの問題を最小限に抑える必要があります。

t=$[$(date +%s%N)/1000000]<---私のソリューション、この場合の固定点は1970年1月1日です。だがダブルデートコールのため根本的に悪い状況になった。

printf "t=%d\n" $[$(date +%s%N)/1000000]<--- まさにprintfを使うことです。

t=$(date +%s)$[10#$(date +%N)/1000000]<---ひどい例です。前のゼロを削除してから再入力する必要があるようです。

printf "t=%d%03d\n" $(date +%s) $[10#$(date +%N)/1000000]<--- まさにprintfを使うことです。

より良い(賢い)アドバイスはありますか?

編集(追加):

t=$(date +%s%N)それではprintf "%s\n" ${t::13}<---私の考えには一行でもないようだが。

答え1

bash5+から始まる簡単な解決策があります。

$ printf "%.3f\n" $EPOCHREALTIME
1566917328.786

この点が必要ない場合:

printf "%s\n" "$((${EPOCHREALTIME/.}/1000))"

1行のテキスト、アトミック(内部bash変数への1回の呼び出し)、軽量で量子化または丸めの問題のないエポック以降の時間をミリ秒単位で提供します。

答え2

@Isaacが指摘したように、dateGNUやast-openなどをサポートする実装を使用すると、それを使用して精度を制限できますが、%N%s%3Nksh93date できるast-openの組み込みバージョンで作成されましたが、dateこのdateコマンドは組み込まれていません。開始には数百または数千マイクロ秒かかり、日付とその後の印刷にははるかにかかります。

bash形式のサブセットは実際にはコピーされますが、一部はksh93 printf '%(...)T'コピーされません%N

ksh93ここでは、またはなどの高度なシェルを使用する必要があるようですzsh

これらのシェルは、変数に$SECONDSシェルが始まってからの時間を記録することができます(そして任意の値にリセットすることもできます)浮動小数点:

$ typeset -F SECONDS=0; date +%s%3N; echo $SECONDS
1506318780647
0.0017870000

dateここでGNUを実行するのに1787マイクロ秒かかりました。

$((SECONDS*1000))以下を使用してミリ秒をksh93取得できます。

浮動小数点数のエポック時間には、次のものがzshあります$EPOCHREALTIME

$ zmodload zsh/datetime
$ echo $EPOCHREALTIME
1506318947.2758708000

動作ksh93します"$(printf '%(%s.%N)T' now)"ksh93コマンドの置き換えはプロセスを分岐せず、組み込みパイプを使用しないため、他のBourneと同じシェルほど高価ではありません)。

以下を使用して変数を定義することもできます$EPOCHREALTIME

$ EPOCHREALTIME.get() { .sh.value=$(printf "%(%s.%6N)T");
$ echo "$EPOCHREALTIME"
1506333341.962697

set -o xtrace自動タイムスタンプの場合とaを使用して$PS4現在の時刻を印刷することもできます。存在するzsh

$ zsh -c 'PS4="+%D{%s.%.}> "; set -x; sleep 1; date +%s.%N'
+1506332128.753> sleep 1
+1506332129.754> date +%s.%N
1506332129.755322928

ksh93から:

$ ksh -c 'PS4="+\$(printf "%(%s.%3N)T")> "; set -x; sleep 1; date +%s.%N'
+1506332247.844> sleep 1
+1506332248.851> date +%s.%N
1506332248.853111699

moreutilsユースケースに応じてタイムスタンプを使用することもできますts

$ (date +%s.%6N; date +%s.%6N) | ts %.s
1506319395.000080 1506319394.970619
1506319395.000141 1506319394.971972

tsパイプを介して出力から1行を読み取るのにかかる時間を提供します)。date

または、出力行間の時間に対して、次のようにします。

$ (date +%s.%6N; date +%s.%6N) | ts -i %.s
0.000011 1506319496.806554
0.000071 1506319496.807907

特定のコマンド(パイプライン)を実行するのにかかる時間を確認するには、キーワードを使用してフォーマットを次のtimeように調整することもできます。$TIMEFORMATbash

$ TIMEFORMAT=%E; time date
Mon 25 Sep 09:51:41 BST 2017
0.002

これらの時間形式のガイドラインはもともとcshから来ました(逆にbashGNUzshtime非常に小さなサブセットのみをサポートしています)。 (t)cshでは、$time特殊変数を設定して各コマンドの時間を測定できます。

$ csh -xc 'set time = (0 %E); sleep 1; sleep 2'
set time = ( 0 %E )
sleep 1
0:01.00
sleep 2
0:02.00

(ここで、最初の数字(0ここ)は、対応する数秒以上かかるコマンドの時間を測定する必要があることを示し、2番目の数字はフォーマットを指定します。

答え3

  1. まず、このdateツールはbashの一部ではなく、外部ツールです。
  2. Bash自体は、外部コマンドなしでこれを行うことはできません。
  3. 外部コマンドを使用してこれを実行すると、1行の基準に失敗します。

したがって、これを行うことはできません。

ただし、2行を許可したり、コメントに書かれているようにこれに対する関数を作成すれば可能です。

拡大する:作成した bash 行の中で最も簡単な行ではないが、最新の bash(>4.2) では 1 行コマンドでもこれを行うことができます。他の答えを確認してください。

答え4

長すぎます。

$ date +'%s%3N'
1506298414529

強く打つ

Bash 4.2以降、厳密なbashソリューション(外部​​実行ファイルなし)を使用できます。

$ printf '%(%s)T\n' "-1"
1506298414

$ printf '%(%Y%m%d-%H:%M:%S)T\n' "-1"
20170924-20:13:34

しかし、まだミリ秒やナノ秒は許可されていません。

日付

ミリ秒またはナノ秒を取得するには、次のようにGNU Dateを使用する必要があります。

$ printf '%s\n' "$(date +'%Y%m%d-%H:%M:%S.%N')"
20170924-20:13:34.326113922

または

$ printf '%s\n' "$(date +'%s.%N')"
1506298414.529678016

小数秒の3桁の制限は、%.3fprintf形式を使用して生成できます。

$ printf '%.3f\n' "$(date +'%s.%N')"
1506298414.529

あるいは、より良い方法は、日付ナノ秒形式で許容される桁数を減らす関数を使用することです。

$ printf '%s\n' "$(date +'%s.%3N')"
1506298414.529

その後、ポイントを削除できます。

$ printf '%s\n' "$(date +'%s%3N')"
1506298414529

もちろん、この場合、より単純な解決策(printfがなく正確に要求されたものではない)がより適切に見えます。

$ date +'%s%3N'
1506298414529

関連情報