シェル:バッシュ。
目標: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が指摘したように、date
GNUやast-openなどをサポートする実装を使用すると、それを使用して精度を制限できますが、%N
%s%3N
ksh93
date
できる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
ように調整することもできます。$TIMEFORMAT
bash
$ TIMEFORMAT=%E; time date
Mon 25 Sep 09:51:41 BST 2017
0.002
これらの時間形式のガイドラインはもともとcshから来ました(逆にbash
GNUzsh
はtime
非常に小さなサブセットのみをサポートしています)。 (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
- まず、この
date
ツールはbashの一部ではなく、外部ツールです。 - Bash自体は、外部コマンドなしでこれを行うことはできません。
- 外部コマンドを使用してこれを実行すると、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桁の制限は、%.3f
printf形式を使用して生成できます。
$ 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