PS1プロンプトに経過時間が表示されます。

PS1プロンプトに経過時間が表示されます。

現在、これを使用して bash プロンプトに現在時刻を表示します。

PS1=\[\e[0;32m\]\t \W>\[\e[1;37m\]

20:42:23 ~>

最後のプロンプトから経過した時間を表示できますか?たとえば、

00:00:00 ~> sleep 10
00:00:10 ~> sleep 20
00:00:20 ~>

これは以下に関連しています。バックグラウンドスクリプトで定期的にPS1を変更できますか?

答え1

1つのアプローチは、bashのPROMPT_COMMAND関数を使用してPS1を変更するコードを実行することです。以下の関数は、最初に送信したものの更新版です。この関数は2つの環境変数が少なく、既存の変数が破損しないように「_PS1_」プレフィックスを付けます。

prompt_command() {
  _PS1_now=$(date +%s)
  PS1=$( printf "\[\e[0;32m\]%02d:%02d:%02d \W>\[\e[1;37m\] " \
           $((  ( _PS1_now - _PS1_lastcmd ) / 3600))         \
           $(( (( _PS1_now - _PS1_lastcmd ) % 3600) / 60 )) \
           $((  ( _PS1_now - _PS1_lastcmd ) % 60))           \
       )
  _PS1_lastcmd=$_PS1_now
}
PROMPT_COMMAND='prompt_command'
_PS1_lastcmd=$(date +%s)

始めるには.bash_profileに入れてください。

プロンプトパラメータと一致するようにパラメータをすばやく入力する必要があることに注意してくださいsleep。時間は、実際にコマンドを入力するのにかかる時間を含むプロンプト間の差です。

00:00:02 ~> sleep 5   ## here I typed really quickly
00:00:05 ~> sleep 3   ## here I took about 2 seconds to enter the command
00:00:10 ~> sleep 30 ## more slow typing
00:01:35 ~>

後で追加した内容:

現在削除されている@Cyrusの答えに基づいて、追加の変数で環境を複雑にしないバージョンは次のとおりです。

PROMPT_COMMAND='
    _prompt(){
        PROMPT_COMMAND="${PROMPT_COMMAND%-*}-$SECONDS))\""
        printf -v PS1 "\[\e[0;32m\]%02d:%02d:%02d \W>\[\e[1;37m\] " \
                      "$(($1/3600))" "$((($1%3600)/60))" "$(($1%60))"
    }; _prompt "$((SECONDS'"-$SECONDS))\""

追加の遅い追加:

Bash バージョン 4.2 から開始echo $BASH_VERSION)、date新しいprintf形式の文字列を使用して外部呼び出しを防ぐ$(date +%s)ことができます$(printf '%(%s)T' -1)バージョン 4.3 以降-1、「引数がないことを意味する」に依存するために引数を省略できます。「行動。

答え2

PS1[3]=$SECONDS
PS1='${PS1[!(PS1[1]=!1&(PS1[3]=(PS1[2]=$SECONDS-${PS1[3]})/3600))
   ]#${PS1[3]%%*??}0}$((PS1[3]=(PS1[2]/60%60),  ${PS1[3]})):${PS1[1
   ]#${PS1[3]%%*??}0}$((PS1[3]=(PS1[2]%60),     ${PS1[3]})):${PS1[1
   ]#${PS1[3]%%*??}0}$((PS1[3]=(SECONDS),       ${PS1[3]})):'$PS1

これはフォーマットを計算的に処理するため、数回拡張されますが、サブシェルやパイプは実行されません。

単にこれを$PS1配列として扱い、より高いインデックスを使用してプロンプト間に必要なすべての/必要な状態を保存/計算します。他のシェルの状態には影響しません。

00:00:46:[mikeserv@desktop tmp]$
00:00:01:[mikeserv@desktop tmp]$
00:00:00:[mikeserv@desktop tmp]$
00:00:01:[mikeserv@desktop tmp]$
00:00:43:[mikeserv@desktop tmp]$ sleep 10
00:00:33:[mikeserv@desktop tmp]$ sleep 10
00:00:15:[mikeserv@desktop tmp]$
00:00:15:[mikeserv@desktop tmp]$
00:00:02:[mikeserv@desktop tmp]$
00:02:27:[mikeserv@desktop tmp]$

少し割って見ることができます...

まず、現在の値を保存します$SECONDS

PS1[3]=$SECONDS

次に、常に正しい値を設定すると同時に自己参照を作成するよう$PS1[0]に独自の再帰を定義します。$PS1[1-3]この部分を得るには、シェル数学式が評価される順序を考慮する必要があります。最も重要なことは、シェル数学が常にシェル数学の最後の作業であることです。まず、シェルは値を拡張します。このように割り当てを使用した後、数学式でシェル変数の以前の値を参照できます$

まず、簡単な例を挙げましょう。

x=10; echo "$(((x+=5)+$x+x))" "$x"

40 15

シェルは最初に参照された位置値をドル記号で置き換えて$x文を評価するので、$式は次のようになります。

(x+=5)+10+x

...シェルは値に5を加算し、参照変数に実際に割り当てられた値のみを維持しながら、式全体を$x展開します。x+10+xしたがって、数学的表現の拡張値は40ですが、最終値は$x15です。

これは$PS1主に方程式が機能する方法ですが、配列索引付けに使用される追加の数学的拡張/評価が必要です。

PS1='${PS1[!(PS1[1]=!1&(...))]#...}...'

私がなぜそこを使うことを選んだのか分かりませんPS1[1]=!1。おそらく愚かな美学のようです。ただし、$PS1[1]パラメータ置換のために拡張するとゼロが割り当てられます。 0のビットAND値と異なる値は常に0になりますが、&&一番左のデフォルト値が0の場合、ブール値のように短絡されないため、角括弧式は毎回評価されます。もちろん、最初の省略記号は$PS1[2,3]初期値が設定される位置であるため、これは重要です。

それにもかかわらず、$PS1[1]プロンプト抽選の間で操作されても、ここではゼロが保証されます。括弧の中に...

PS1[3]=(PS1[2]=$SECONDS-${PS1[3]})/3600

$PS1[2]...合計の差が割り当てられ、その値と3600の商が割り当てられます。すべての値はここで初期化されます。だから:$PS1[3]$SECONDS$PS1[3]

${PS1[1]#${PS1[3]%%*??}0}

...2桁以上の場合、内部的にnullに拡張され、0であることがわかっているので、$PS1[3]ifをnullに置き換えることができるので、elseもその値に拡張できます。このように、割り当て反復当たり単一の数値のみが先行ゼロに拡張され、それ自体がモジュロ60に直ちに拡張されると同時に、各時間、分、秒に次の連続小値が割り当てられる。$PS1[1]$PS1[3]$PS1[1]$PS1[3]$PS1[3]

$PS1[3]次にヒントを描画するときに$SECONDS再比較できるように、最後の反復を現在の値で上書きするまで洗い流して繰り返します。$SECONDS

答え3

これまで私が見つけた最高のソリューションは次のとおりです。https://github.com/jichu4n/bash-command-timer

コマンドを実行した後、右側に経過時間が印刷されるため、[ 1s011 | May 25 15:33:44 BST ]PS1は複雑になりません。

文字列全体と時間形式を設定できます。色と精度も設定可能です。一部のミニマリストにとって、これはやや過度になるかもしれないことを知っていますが、かなりクールです。

答え4

Bash以降非常に可能4.4PS0、環境変数を紹介します。

export PS0='$(date +%s%03N > ~/.execStart.$$)'

printElapsedCommandTime () {
    local execStart execEnd execDur elaStr
    if [ -e ~/.execStart.$$ ]; then
        read execStart < ~/.execStart.$$ 2>/dev/null
        rm -f ~/.execStart.$$
        if [ -n "$execStart" ]; then
            execEnd=`date +%s%03N`
            execDur=$((execEnd-execStart))
            printf -v elaStr "Ela %u.%03u" $((execDur / 1000)) $((execDur % 1000))
            printf "%*s\e[32;7m%s\e[0m\n" $((COLUMNS-${#elaStr})) "" "$elaStr"
        fi
    fi
}
export PROMPT_COMMAND='printElapsedCommandTime'

PS0(ディスプレイ後ろにBashはコマンドを読みましたが、今後Bashが実行を開始しました。)出力を一時ファイルに保存しますdate +%s%03N。これはエポック秒とナノ秒の最初の3桁です。全体的な効果はエポックマイクロ秒を保存することです。

PROMPT_COMMAND(評価する後ろにBashはコマンドの実行を完了しましたが、今後Bashはデフォルトのプロンプトを表示しましたPS1。再びEpochマイクロ秒を見つけて、一時ファイルに保存されている測定値を減算します。

経過時間は右側の別の行に表示されます。低いレベルはprintf少し難しいです。

  • 書式指定子の%*s消費二つパラメータ、整数、および文字列。前者は、後者の印刷に使用する列数を表します。私たちが提供する2つのパラメータはN =$((COLUMNS-${#elaStr}))で、空の文字列は""Nスペースを印刷することです。
  • \e[32;7m7緑色(" " 32)背景の逆相ビデオ( " ")テキストを要求します。
  • %s私たちの文字列を消費することです$elaStr
  • \e[0mフォントの色を通常の色にリセットします。

吹く5.0EPOCHREALTIME2回呼び出すのを防ぐ環境変数が導入されましたdate(1)EPOCHREALTIMEはマイクロ秒単位の小数秒です。.削除すると同じ出力になるため、改善されたdate +%s%03N解決策を得るには2つの小さな変更を行うだけです。

export PS0='echo ${EPOCHREALTIME/./} > ~/.execStart.$$)'   ### change here...

printElapsedCommandTime () {
    local execStart execEnd execDur elaStr
    if [ -e ~/.execStart.$$ ]; then
        read execStart < ~/.execStart.$$ 2>/dev/null
        rm -f ~/.execStart.$$
        if [ -n "$execStart" ]; then
            execEnd=`${EPOCHREALTIME/./}                   ### ...and here
            execDur=$((execEnd-execStart))
            printf -v elaStr "Ela %u.%03u" $((execDur / 1000)) $((execDur % 1000))
            printf "%*s\e[32;7m%s\e[0m\n" $((COLUMNS-${#elaStr})) "" "$elaStr"
        fi
    fi
}
export PROMPT_COMMAND='printElapsedCommandTime'

関連情報