【发布时间】:2010-04-24 13:37:11
【问题描述】:
有没有像time这样的命令可以显示shell上最后或过去执行的命令的运行时间详情?
【问题讨论】:
标签: linux bash macos unix shell
有没有像time这样的命令可以显示shell上最后或过去执行的命令的运行时间详情?
【问题讨论】:
标签: linux bash macos unix shell
zsh 有一些内置功能可以计算命令需要多长时间。
如果您启用了 inc_append_history_time 选项
setopt inc_append_history_time
然后运行每个命令所花费的时间会保存在您的历史记录中,然后可以使用history -D查看。
【讨论】:
我不知道,它在 bash 中如何,但在 zsh 中你可以定义 preexec 和 precmd 函数,以便它们将当前时间保存到变量 $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])。
更新2:
在 bash 中找到了支持 zsh 样式的 precmd 和 preexec 的脚本。也许您需要删除typeset -ig(我曾经只是强制$_start 为整数)并将set -A var ... 替换为var=( ... ) 以使其正常工作。而且我不知道如何在 bash 中对数组进行切片并获取它们的长度。
脚本:http://www.twistedmatrix.com/users/glyph/preexec.bash.txt
更新3:
发现一个问题:如果你用空行点击返回,preexec 不会运行,而 precmd 会运行,所以你将在 $_elapsed 数组中得到无意义的值。为了解决这个问题,请使用以下代码替换 precmd 函数:
precmd () {
(( _start >= 0 )) && set -A _elapsed $_elapsed $(( SECONDS-_start ))
_start=-1
}
【讨论】:
EXTENDED_HISTORY 选项结合起来以提高健壮性?只是扔一个adea。我没有超过 10s 的思考时间,我的睡眠时间已经结束了(等待脚本完成它的工作)。
编辑 3:
这个答案的结构:
根据上面的大纲按其部分标记的答案:
第 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。
【讨论】:
我认为您正在运行需要很长时间的命令,并且在开始时没有意识到您想要计算它们需要多长时间才能完成。在 zsh 中,如果您将环境变量 REPORTTIME 设置为一个数字,则任何花费超过该秒数的命令都将打印它所花费的时间,就好像您已经在它前面运行了 time 命令一样。你可以在你的 .zshrc 中设置它,这样长时间运行的命令总是会打印它们的时间。请注意,睡眠时间(相对于用户/系统时间)不计入触发计时器,但仍会被跟踪。
【讨论】:
我认为您只能获取使用命令“时间”运行的命令的计时统计信息。
来自手册页:
时间 [选项] 命令 [参数...]
描述 time 命令使用给定的参数运行指定的程序命令。当命令完成时, time 向标准错误写入一条消息,提供有关此程序运行的计时统计信息。
【讨论】:
我编写了一个工具(discalimer!),它通过劫持到正在运行的 shell 进程(目前只有 支持 bash)。与此处发布的其他解决方案相比,它还正确跟踪异步命令的运行时间,例如sleep 5 &.
在这里查看:
【讨论】:
可以使用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
注意:如果您的 $HISTCONTROL 中有 ignoredups,则不会报告重新运行的命令。
参考(抄自我自己对类似问题的回答):
Use PS0 and PS1 to display execution time of each bash command
【讨论】: