最后一个命令的挂壁时间怎么能放在Bash提示符下?

有没有办法在Bash提示符中embedded最后一个命令的经过时间? 我希望看到这样的东西:

[last: 0s][/my/dir]$ sleep 10 [last: 10s][/my/dir]$ 

背景

我经常进行长时间的数据处理工作,了解他们已经工作了多长时间是非常有用的,所以我可以估计未来工作需要多长时间。 对于非常规的任务,我会继续使用适当的logging技术严格logging这些信息。 对于不那么正式的任务,我只是随着time命令。

自动time每一个交互式命令并且将计时信息打印成几个字符而不是三行是很好的。

你可以利用这个zsh-borrowed钩子bash: http : //www.twistedmatrix.com/users/glyph/preexec.bash.txt

使用此钩子(Mac OS X)完成计时: 使用Growl监视长时间运行的shell命令

这是最小的独立代码来实现你想要的:

 function timer_start { timer=${timer:-$SECONDS} } function timer_stop { timer_show=$(($SECONDS - $timer)) unset timer } trap 'timer_start' DEBUG PROMPT_COMMAND=timer_stop PS1='[last: ${timer_show}s][\w]$ ' 

使用您的回复和其他线程,我写了这个提示,我想与你分享。 我在截图中看到了:

  • 白色:最后的返回码
  • 绿色和刻度标记表示成功(返回码为0)
  • 红色和十字标记表示错误(返回码大于0)
  • (绿色或红色):括号内的最后一个命令执行时间
  • (绿色或红色):当前date时间(\ t)
  • (如果不是root,则为绿色,如果是root,则为Red):login的用户名
  • (绿色):服务器名称
  • (蓝色):pwd目录和通常的$

自定义提示

这里是放在〜/ .bashrc文件中的代码:

 function timer_now { date +%s%N } function timer_start { timer_start=${timer_start:-$(timer_now)} } function timer_stop { local delta_us=$((($(timer_now) - $timer_start) / 1000)) local us=$((delta_us % 1000)) local ms=$(((delta_us / 1000) % 1000)) local s=$(((delta_us / 1000000) % 60)) local m=$(((delta_us / 60000000) % 60)) local h=$((delta_us / 3600000000)) # Goal: always show around 3 digits of accuracy if ((h > 0)); then timer_show=${h}h${m}m elif ((m > 0)); then timer_show=${m}m${s}s elif ((s >= 10)); then timer_show=${s}.$((ms / 100))s elif ((s > 0)); then timer_show=${s}.$(printf %03d $ms)s elif ((ms >= 100)); then timer_show=${ms}ms elif ((ms > 0)); then timer_show=${ms}.$((us / 100))ms else timer_show=${us}us fi unset timer_start } set_prompt () { Last_Command=$? # Must come first! Blue='\[\e[01;34m\]' White='\[\e[01;37m\]' Red='\[\e[01;31m\]' Green='\[\e[01;32m\]' Reset='\[\e[00m\]' FancyX='\342\234\227' Checkmark='\342\234\223' # Add a bright white exit status for the last command PS1="$White\$? " # If it was successful, print a green check mark. Otherwise, print # a red X. if [[ $Last_Command == 0 ]]; then PS1+="$Green$Checkmark " else PS1+="$Red$FancyX " fi # Add the ellapsed time and current date timer_stop PS1+="($timer_show) \t " # If root, just print the host in red. Otherwise, print the current user # and host in green. if [[ $EUID == 0 ]]; then PS1+="$Red\\u$Green@\\h " else PS1+="$Green\\u@\\h " fi # Print the working directory and prompt marker in blue, and reset # the text color to the default. PS1+="$Blue\\w \\\$$Reset " } trap 'timer_start' DEBUG PROMPT_COMMAND='set_prompt' 

另一个非常小的方法是:

 trap 'SECONDS=0' DEBUG export PS1='your_normal_prompt_here ($SECONDS) # ' 

这显示了自上次简单命令启动以来的秒数。 如果您只是在不input命令的情况下直接按下Enter键,计数器就不会被重置 – 当您只想查看自上次做任何事情以后terminal已经启动多长时间时,该计数器可能非常方便。 在Red Hat和Ubuntu中,它工作正常。 在Cygwin下它并不适用于我,但是我不确定这是一个bug还是只是在Windows下运行Bash的限制。

这种方法的一个可能的缺点是你保持重新设置SECONDS,但是如果你真的需要保留SECONDS作为自从初始shell调用以来的秒数,你可以为PS1计数器创build你自己的variables,而不是直接使用SECONDS。 另一个可能的缺点是,像“999999”这样的大秒值可能会更好地显示为天+小时+分钟+秒,但是可以很容易地添加一个简单的filter,例如:

 seconds2days() { # convert integer seconds to Ddays,HH:MM:SS printf "%ddays,%02d:%02d:%02d" $(((($1/60)/60)/24)) \ $(((($1/60)/60)%24)) $((($1/60)%60)) $(($1%60)) | sed 's/^1days/1day/;s/^0days,\(00:\)*//;s/^0//' ; } trap 'SECONDS=0' DEBUG PS1='other_prompt_stuff_here ($(seconds2days $SECONDS)) # ' 

这将“999999”翻译为“11日,13:46:39”。 结束sed将“1天”更改为“1天”,并删除“0天,00:”等空的主要值。 适应口味。

如果你在开始你的长期工作之前还没有设定任何其他的答案,而你只是想知道工作花了多长时间,你可以做简单的事情

 $ HISTTIMEFORMAT="%s " history 2 

它会回复类似的东西

  654 1278611022 gvn up 655 1278611714 HISTTIMEFORMAT="%s " history 2 

然后你可以直接减去两个时间戳(任何人都知道如何捕获shell内置历史命令的输出)?

我从Ville Laurikari那里得到了答案,并使用time命令对其进行了改进,以显示亚秒级精度:

 function timer_now { date +%s%N } function timer_start { timer_start=${timer_start:-$(timer_now)} } function timer_stop { local delta_us=$((($(timer_now) - $timer_start) / 1000)) local us=$((delta_us % 1000)) local ms=$(((delta_us / 1000) % 1000)) local s=$(((delta_us / 1000000) % 60)) local m=$(((delta_us / 60000000) % 60)) local h=$((delta_us / 3600000000)) # Goal: always show around 3 digits of accuracy if ((h > 0)); then timer_show=${h}h${m}m elif ((m > 0)); then timer_show=${m}m${s}s elif ((s >= 10)); then timer_show=${s}.$((ms / 100))s elif ((s > 0)); then timer_show=${s}.$(printf %03d $ms)s elif ((ms >= 100)); then timer_show=${ms}ms elif ((ms > 0)); then timer_show=${ms}.$((us / 100))ms else timer_show=${us}us fi unset timer_start } trap 'timer_start' DEBUG PROMPT_COMMAND=timer_stop PS1='[last: ${timer_show}][\w]$ ' 

当然,这需要一个过程开始,所以它效率不高,但仍然足够快,你不会注意到。

我发现trap ... DEBUG每次调用$PROMPT_COMMAND时都会运行trap ... DEBUG ,重置计时器,因此总是返回0。

但是,我发现historylogging的时代,我挖掘到这些来得到我的答案:

 HISTTIMEFORMAT='%s ' PROMPT_COMMAND=" START=\$(history 1 | cut -f5 -d' '); NOW=\$(date +%s); ELAPSED=\$[NOW-START]; $PROMPT_COMMAND" PS1="\$ELAPSED $PS1" 

这不是完美的,

  • 如果history没有注册命令(例如重复或忽略的命令),则开始时间将是错误的。
  • 多行命令不会从history中正确提取date。

PS1会在你身上工作吗?

它没有给出经过的时间,但应该很容易在必要时减去时间。

 $ export PS1='[\t] [\w]\$ ' [14:22:30] [/bin]$ sleep 10 [14:22:42] [/bin]$ 

根据OP的评论,他已经在使用\ t。 如果你可以使用tcsh而不是bash,你可以设置时间variables。

 /bin 1 > set time = 0 /bin 2 > sleep 10 0.015u 0.046s 0:10.09 0.4% 0+0k 0+0io 2570pf+0w /bin 3 > 

您可以将打印的格式更改为不那么难看(请参见tcsh手册页)。

 /bin 4 > set time = ( 0 "last: %E" ) /bin 5 > sleep 10 last: 0:10.09 /bin 6 > 

我不知道在bash中有类似的设施