有没有办法找到shell中最后执行的命令的运行时间?

时间:2010-04-24 13:37:11

标签: linux bash macos unix shell

是否有像time这样的命令可以显示shell上最后或过去执行的命令的运行时间细节?

7 个答案:

答案 0 :(得分:13)

我不知道,它是如何在bash中,但在zsh中你可以定义preexecprecmd函数,以便它们将当前时间保存到变量$STARTTIME(preexec)和$ENDTIME(precmd),这样您就可以找到大致的运行时间。或者,您可以定义accept-line函数,以便在每个命令之前添加time

<强>更新: 这是代码,它将在$_elapsed数组中存储已用时间:

preexec () {
   (( $#_elapsed > 1000 )) && set -A _elapsed $_elapsed[-1000,-1]
   typeset -ig _start=SECONDS
}
precmd() { set -A _elapsed $_elapsed $(( SECONDS-_start )) }

然后如果您运行sleep 10s

% set -A _elapsed # Clear the times
% sleep 10s
% sleep 2s ; echo $_elapsed[-1]
10
% echo $_elapsed
0 10 0

不需要四个变量。名称或额外延迟没有问题。请注意,$_elapsed数组可能会变得非常大,因此您需要删除第一项(使用以下代码完成此操作:(( $#_elapsed > 1000 )) && set -A _elapsed $_elapsed[-1000,-1])。

<强> UPDATE2 : 在bash中找到支持zsh样式的precmd和preexec的脚本。也许您需要删除typeset -ig(我只是强迫$_start为整数)并将set -A var ...替换为var=( ... )以使其正常工作。而且我不知道如何对阵列进行切片并在bash中获得它们的长度。

脚本:http://www.twistedmatrix.com/users/glyph/preexec.bash.txt

<强> UPDATE3 : 发现一个问题:如果你用空行命中返回preexec不运行,而precmd则运行,所以你将在$_elapsed数组中得到无意义的值。为了解决此问题,请使用以下代码替换precmd函数:

precmd () {
   (( _start >= 0 )) && set -A _elapsed $_elapsed $(( SECONDS-_start ))
   _start=-1 
}

答案 1 :(得分:5)

编辑3:

这个答案的结构:

  1. 没有现成的方法来计算已经运行的命令
  2. 有些方法可以推断出对命令运行时间的估计。
  3. 显示了概念证明(从假设不能完成并以假设错误的结论结束)。
  4. 您可以预先设置黑客,记录您运行的每个命令的已用时间
  5. 结论
  6. 根据上述大纲,其部分标注的答案:

    第1部分 - 简短的回答是“不”

    原始

    不,抱歉。您必须使用time

    第2部分 - 也许您可以推断出结果

    在某些情况下,如果某个程序在日志文件中写入输出文件或信息,您可能会推断出运行时间,但这可能是特定于程序的,只是猜测。如果在Bash中设置了HISTTIMEFORMAT,则可以查看历史文件中的条目,以了解程序何时启动。但是没有记录结束时间,因此如果在您感兴趣的项目之后立即启动了另一个程序,则只能推断出一个持续时间。

    第3部分 - 假设是伪造的

    假设:空闲时间将按经过时间计算

    修改

    这是一个说明我的观点的例子。它基于 ZyX 的建议,但使用其他方法也类似。

    zsh

    % precmd() { prevstart=start; start=$SECONDS; }
    % preexec() { prevend=$end; end=$SECONDS; }
    % echo "T: $SECONDS ps: $prevstart pe: $prevend s: $start e: $end"
    T: 1491 ps: 1456 pe: 1458 s: 1459 e: 1491
    

    现在我们等待......让我们说15秒,然后:

    % echo "T: $SECONDS"; sleep 10
    T: 1506
    

    现在我们等待...让我们说20秒,然后:

    % echo "T: $SECONDS ps: $prevstart pe: $prevend s: $start e: $end"
    T: 1536 ps: 1492 pe: 1506 s: 1516 e: 1536
    

    如您所见,我 错误 。开始时间(1516)减去上一个结束时间(1506) 命令的持续时间(sleep 10)。 这也表明我在函数中使用的变量需要更好的名称。

    假设伪造 - 可以获得正确的经过时间而不包括空闲时间

    第4部分 - 记录每个命令所用时间的黑客

    编辑2:

    以下是 ZyX的答案中的函数的Bash等价物(它们需要链接到那里的脚本):

    preexec () {
       (( ${#_elapsed[@]} > 1000 )) && _elapsed=(${_elapsed[@]: -1000})
       _start=$SECONDS
    }
    
    precmd () {
       (( _start >= 0 )) && _elapsed+=($(( SECONDS-_start )))
       _start=-1 
    }
    

    安装preexec.bash(从链接脚本)并创建上述两个函数后,示例运行如下所示:

    $ _elapsed=() # Clear the times
    $ sleep 10s
    $ sleep 2s ; echo ${_elapsed[@]: -1}
    10
    $ echo ${_elapsed[@]}
    0 10 2
    

    第5部分 - 结论

    使用time

答案 2 :(得分:4)

我认为你运行的命令需要花费很长时间才能在开始时没有意识到你想花多长时间完成它们。在zsh中,如果将环境变量REPORTTIME设置为一个数字,则任何超过该秒数的命令都将打印时间,就像您使用前面的time命令运行它一样。您可以在.zshrc中设置它,以便长时间运行的命令始终打印时间。请注意,睡眠时间(与用户/系统时间相反)不计入触发计时器,但仍会被跟踪。

答案 3 :(得分:3)

由于其他人回答了这些问题,世界可能会有所改变。

zsh有一些内置功能可以计算命令的持续时间。

如果您使用

启用inc_append_history_time选项

setopt inc_append_history_time

然后,运行每个命令所花费的时间将保存在您的历史记录中,然后可以使用history -D进行查看。

答案 4 :(得分:1)

我认为您只能使用命令'time'获取运行命令的时序统计信息。

从手册页:

  

time [options]命令[arguments ...]

     

说明          time命令使用给定的参数运行指定的程序命令。命令完成后,          time将消息写入标准错误,给出有关此程序运行的计时统计信息。

答案 5 :(得分:0)

我编写了一个工具(discalimer!),它通过劫持进入正在运行的shell进程(目前仅)来跟踪命令的开始和停止时间以及其他命令元数据(例如cwd或修改的文件) bash 受支持)。与此处发布的其他解决方案相比,它还可以正确跟踪异步命令的运行时,例如sleep 5 &
在这里查看:

https://github.com/tycho-kirchner/shournal

答案 6 :(得分:0)

可以使用带有纪元秒 template<class TypeName> class MyQueue { }; history 命令和内置变量 %s 仅利用 $EPOCHSECONDS 来计算命令何时完成。

$PROMPT_COMMAND

注意:如果您的 # Save start time before executing command (does not work due to PS0 sub-shell) # preexec() { # STARTTIME=$EPOCHSECONDS # } # PS0=preexec # Save end time, without duplicating commands when pressing Enter on an empty line precmd() { local st=$(HISTTIMEFORMAT='%s ' history 1 | awk '{print $2}'); if [[ -z "$STARTTIME" || (-n "$STARTTIME" && "$STARTTIME" -ne "$st") ]]; then ENDTIME=$EPOCHSECONDS STARTTIME=$st else ENDTIME=0 fi } __timeit() { precmd; if ((ENDTIME - STARTTIME >= 0)); then printf 'Command took %d seconds.\n' "$((ENDTIME - STARTTIME))"; fi # Do not forget your: # - OSC 0 (set title) # - OSC 777 (notification in gnome-terminal, urxvt; note, this one has preexec and precmd as OSC 777 features) # - OSC 99 (notification in kitty) # - OSC 7 (set url) - out of scope for this question } export PROMPT_COMMAND=__timeit 中有 ignoredups,则不会报告重新运行的命令。

参考(复制自我自己对类似问题的回答):

Use PS0 and PS1 to display execution time of each bash command