Bash:PROMPT_COMMANDにHistory -aを追加すると、最後のコマンドの停止時間が誤って計算されます。

Bash:PROMPT_COMMANDにHistory -aを追加すると、最後のコマンドの停止時間が誤って計算されます。

最後のコマンドの停止時間を計算するには、次のコード(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 #2後に追加すると誤った結果が表示されるのはなぜcode #1ですか?code #1どうすれば修正できますか?

答え1

一連のイベント(読者が何がうまくいくか${var:-someval}を知っていると仮定):

  • いくつかのコマンドを入力してください。
  • Enter キーを押すとDEBUGトラップが実行されます。
    • timer_start=${timer_start:-$(timer_now)}
  • その後、コマンドを実行します。
  • それからset_prompt実行されました。
    • バラバラでは
    • unset timer_start- タイマーが再起動します。
  • 次に、以前DEBUGにトラップを実行します。history -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

関連情報