Bash:将历史 -a 添加到 PROMPT_COMMAND 会导致最后一个命令的挂起时间计算不正确

Bash:将历史 -a 添加到 PROMPT_COMMAND 会导致最后一个命令的挂起时间计算不正确

为了计算最后一个命令的挂起时间,我使用以下代码(code #1):

#
# Taken from https://stackoverflow.com/a/34812608/9881330
# Slightly modified.
#
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 () {
    PS1="\n\$?"
    timer_stop
    PS1+=" / $timer_show"
    PS1+="\n\n\[\e]0;\w\a\]\[\e[32m\]\u@\h \[\e[33m\]\w\[\e[0m\]\n\$ "
}

trap 'timer_start' DEBUG
PROMPT_COMMAND='set_prompt'

而且效果非常好:

$ gcc
gcc: fatal error: no input files
compilation terminated.

1 / 108ms

$ date
Sun Dec 27 14:53:10 RTZST 2020

0 / 89.3ms

然而,要解决这个history is lost after ssh connection is reset by peer问题(Bash:ssh 连接被对等方重置后历史记录丢失:如何保存历史记录?),在前面的代码(code #1)之后我添加了这段代码(code #2):

PROMPT_COMMAND="${PROMPT_COMMAND:+${PROMPT_COMMAND/%;};}history -a"

现在,最后一个命令的挂起时间计算不正确(而命令在视觉上像往常一样以毫秒为单位运行):

$ gcc
gcc: fatal error: no input files
compilation terminated.

1 / 1.990s

$ date
Sun Dec 27 14:56:07 RTZST 2020

0 / 3.586s

问题:为什么添加code #2aftercode #1code #1产生错误的结果?怎么修?

答案1

事件链(假设读者知道什么${var:-someval}有效):

  • 您输入一些命令。
  • 当你按下回车键时,DEBUGtrap 就会被执行。
    • timer_start=${timer_start:-$(timer_now)}
  • 然后执行命令。
  • 然后set_prompt就被执行了。
    • 巴拉巴拉,然后
    • unset timer_start- 计时器重新启动。
  • 然后DEBUG之前执行traphistory -a
    • timer_start=${timer_start:-$(timer_now)}
  • 然后history -a就被执行了。
  • 时间流逝,您输入命令。
  • 然后DEBUGtrap 在你输入命令之前执行。
    • timer_start=${timer_start:-$(timer_now)}
    • timer_start已经设置了,所以什么也没有发生。
  • 然后你的命令就会被执行。
  • set_prompt超长,因为它测量的是距离上次prompt_command执行history -a的时间。

history -a例如,在运行之前执行或在运行时set_prompt删除陷阱。DEBUG

相关内容