太长了;博士

太长了;博士

外壳:重击。

目标:获取自某个固定时间点以来的时间 t(以毫秒为单位),适合使用 printf 进行时间戳处理。

条件:解决方案必须通过全行文本测试。

另外:解决方案应该是原子的(是的,对!..)、轻量级、将量化和舍入问题保持在最低限度,等等。

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))"

提供自纪元以来的毫秒时间,全在一行文本中,原子(对内部 bash 变量的一次调用),轻量级,并且没有量化或舍入问题。

答案2

正如 @Isaac 所指出的,通过支持GNU 或 ast-open 等date的实现,您可以使用它来限制精度,但除了在哪里%N%s%3Nksh93date 被制作为 ast-open 的内置版本date,该date命令不是内置的。启动需要几百微秒甚至几千微秒,打印日期和返回还需要更多时间。

bash确实复制了格式的子集ksh93 printf '%(...)T',但没有复制%N部分。

在这里,您似乎需要使用更高级的 shell,例如ksh93zsh

这些 shell 可以使它们的$SECONDS变量记录自 shell 启动以来的时间(并且您也可以重置为任何值)浮点:

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

date这里运行 GNU 花费了 1787 微秒。

您可以使用$((SECONDS*1000))来获取毫秒数,因为两个 shell 都支持浮点算术(注意ksh93遵循区域设置的小数点标记)。

对于作为浮点数的纪元时间,zsh$EPOCHREALTIME

$ zmodload zsh/datetime
$ echo $EPOCHREALTIME
1506318947.2758708000

并且ksh93可以使用"$(printf '%(%s.%N)T' now)"(请注意,ksh93命令替换不会分叉进程,也不使用内置管道,因此不像其他类似 Bourne 的 shell 那样昂贵)。

您还可以$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从 的输出读取行的时间)。date

或者对于输出行之间的时间:

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

如果你想获取运行给定命令(管道)所花费的时间,你还可以使用关键字,用intime调整格式:$TIMEFORMATbash

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

这些时间格式指令最初来自 csh(尽管bash与此相反,zshGNUtime仅支持一个很小的子集)。在 (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此处)表示应该对花费超过那么多秒的命令进行计时,第二个数字指定格式)。

答案3

  1. 首先该date工具不是 bash 的一部分,它是一个外部工具。
  2. 如果没有外部命令,Bash 本身就无法做到这一点。
  3. 使用外部命令执行此操作无法通过您的单行标准。

因此,你不能这样做。

但是,如果您允许 2 行,或者为此编写一个函数,则可以这样做,正如注释中所写的那样。

扩大:您可以使用更新的 bash (>4.2) 来完成此操作,即使作为单行命令,尽管它不会是您编写过的最简单的 bash 行。检查另一个答案。

答案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 日期,如下所示:

$ 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

相关内容