命令完成后的持续时间、开始时间和结束时间

blu*_*ray 5 bash zsh shell-script

我想在命令完成后得到如下报告:

Start Time: 02/01/21 01:27pm
End Time: 02/01/21 02:29pm
Total Duration: 01 Hour 02 Minutes
Run Code Online (Sandbox Code Playgroud)

我发现我可以使用date +"%d/%m/%y %I:%M%P".

例如,

start=$(date +"%d/%m/%y %I:%M%P")
start_duration=$(date +%s)
youtube-dl
end=$(date +"%d/%m/%y %I:%M%P")
end_duration=$(date +%s)
runtime=$((end_duration-start_duration))
echo "Start Time: ${start}"
echo "End Time: ${end}"
Run Code Online (Sandbox Code Playgroud)

几个问题。

  1. 我不明白如何打印 Total Duration: 01 Hour 02 Minutes
  2. 我怎样才能使这个脚本通用,以便我可以使用任何命令,而不仅仅是youtube-dl在这个脚本中。

我试过:

#! /bin/bash

Before=$(date +%s)
echo "$Before"
exec "$@"
ret=$?
After=$(date +%s)
echo "$After"
let Duration=After-Before
echo "$Duration"

if [[ $ret -eq 0 ]]
then
    echo "Start Time: ${Before}"
    echo "End Time: ${After}"
    echo "Total Duration: ${Duration}"
    return $ret
else
    echo "Error: Command [ $@ ] returned $ret"
    echo "Start Time: ${Before}"
    echo "End Time: ${After}"
    echo "Total Duration: ${Duration}"
    return $ret
fi
Run Code Online (Sandbox Code Playgroud)

但是如果我使用它就不起作用 ctrl+c

$ ./reporttime tail -f ~/.xsession-errors
Cinnamon warning: Log level 128: posix_spawn avoided (fd close requested)
Cinnamon warning: Log level 128: posix_spawn avoided (fd close requested)
Cinnamon warning: Log level 128: posix_spawn avoided (fd close requested)
Cinnamon warning: Log level 128: posix_spawn avoided (fd close requested)
Cinnamon warning: Log level 128: posix_spawn avoided (fd close requested)
Cinnamon warning: Log level 128: posix_spawn avoided (fd close requested)
Cinnamon warning: Log level 128: posix_spawn avoided (fd close requested)
Cinnamon warning: Log level 128: posix_spawn avoided (fd close requested)
Cinnamon warning: Log level 128: posix_spawn avoided (fd close requested)
Cinnamon warning: Log level 128: posix_spawn avoided (fd close requested)
Cinnamon warning: Log level 128: posix_spawn avoided (fd close requested)
^C
Run Code Online (Sandbox Code Playgroud)

事实上,之后可能什么都没有执行 exec "$@"

% ./reporttime cat reporttime
1609655953
#! /bin/bash

Before=$(date +%s)
echo "$Before"
exec "$@"
ret=$?
After=$(date +%s)
echo "$After"
let Duration=After-Before
echo "$Duration"

if [[ $ret -eq 0 ]]
then
    echo "Start Time: ${Before}"
    echo "End Time: ${After}"
    echo "Total Duration: ${Duration}"
    return $ret
else
    echo "Error: Command [ $@ ] returned $ret"
    echo "Start Time: ${Before}"
    echo "End Time: ${After}"
    echo "Total Duration: ${Duration}"
    return $ret
fi%                                              
Run Code Online (Sandbox Code Playgroud)

Sté*_*las 6

zsh

zmodload zsh/datetime
TIMEFMT='Total duration for %J: %*E'
preexec() strftime 'Start Time: %d/%m/%y %I:%M%P'
precmd() strftime 'End Time: %d/%m/%y %I:%M%P'
REPORTTIME=0
Run Code Online (Sandbox Code Playgroud)

然后,您将在输入命令行时打印开始时间,在显示下一个提示之前打印结束时间,以及每个非内置命令的持续时间(更准确地说,对于 shell 等待的每个进程) :

$ sleep 1; sleep 2
Start Time: 02/01/21 08:31am
Total duration for sleep 1: 1.002
Total duration for sleep 2: 2.003
End Time: 02/01/21 08:31am
Run Code Online (Sandbox Code Playgroud)

您可以更改REPORTTIME=0REPORTTIME=10例如只报告占用CPU时间(不的超过10秒的命令的时间经过时间),或前缀您希望每个命令时间time

作为需要运行任意命令的脚本:

#! /bin/zsh -
zmodload zsh/datetime
TIMEFMT='Total duration: %*E'
strftime -s start 'Start Time: %d/%m/%y %I:%M%P'
{
  duration=$(
    exec 4>&2 2>&1 1>&3 3>&-
    time "$@" 2>&4 4>&-
  )
} 3>&1
ret=$?

strftime -s end 'End Time: %d/%m/%y %I:%M%P'
print -rlu2 $start $end $duration
exit $ret
Run Code Online (Sandbox Code Playgroud)

进而:

$ ./reporttime sleep 65
Start Time: 02/01/21 09:26am
End Time: 02/01/21 09:26am
Total duration: 1:05.00
Run Code Online (Sandbox Code Playgroud)

除了依赖time,您还可以使用$SECONDS$EPOCHSECONDS特殊变量(或$EPOCHREALTIME/$epochtime如果您想要亚秒级粒度)

#! /bin/zsh -
zmodload zsh/datetime
start=($epochtime)
"$@"
end=($epochtime) ret=$?
strftime >&2 'Start Time: %FT%T.%3.%z' $start
strftime >&2 'End Time: %FT%T.%3.%z' $end
printf >&2 'Total duration: %.3f\n' $((
  end[1] - start[1] + (end[2] - start[2]) / 1e9
))
exit $ret
Run Code Online (Sandbox Code Playgroud)

这次使用标准且明确的时间格式:

$ ./reporttime2 sleep 1
Start Time: 2021-01-02T09:50:49.261+0000
End Time: 2021-01-02T09:50:50.264+0000
Total duration: 1.003
Run Code Online (Sandbox Code Playgroud)

如果您仍想在按Ctrl+CCtrl+时报告这些时间\ ,否则会同时终止zsh和正在计时的命令,您可以添加:

trap true INT QUIT
Run Code Online (Sandbox Code Playgroud)

在这些脚本的顶部,shell 拦截这些信号而不是死在那里。不要这样做trap '' INT QUIT会导致信号被完全忽略并且在这种情况下不会终止定时命令。