Bash

Bash:將 history -a 添加到 PROMPT_COMMAND 會使最後一個命令的掛起時間計算不正確

  • December 27, 2020

要計算最後一個命令的掛牆時間,我使用以下程式碼(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: history is lost after ssh connection is reset by peer: how to save the history?),在前面的程式碼(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

問題:為什麼在 makecode #2之後添加code #1code #1產生不正確的結果?怎麼修?

事件鏈(假設讀者知道什麼${var:-someval}有效):

  • 你輸入一些命令。

  • 當您按下輸入鍵時,DEBUG將執行陷阱。

    • timer_start=${timer_start:-$(timer_now)}
  • 然後執行命令。

  • 然後set_prompt被執行。

    • 咩咩咩,然後
    • unset timer_start- 計時器重新啟動。
  • 然後DEBUG在之前執行traphistory -a

    • timer_start=${timer_start:-$(timer_now)}
  • 然後history -a被執行。

  • 時間流逝,你輸入你的命令。

  • 然後DEBUG在您輸入的命令之前執行陷阱。

    • timer_start=${timer_start:-$(timer_now)}
    • 但是timer_start已經設置好了,所以什麼也沒有發生。
  • 然後執行您的命令。

  • set_prompt超長,因為它從最後一次執行開始測量prompt_command時間history -a

history -a例如在執行之前執行set_prompt或刪除DEBUG陷阱。

引用自:https://unix.stackexchange.com/questions/626303