経過時間を表示するPS1プロンプト


10

私は現在、これを使用して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を定期的に変更することは可能ですか?



いいえ、その投稿には回答がありません。新しいプロンプトが表示されたときにのみプロンプトが変わると思います。
TeasingDart 2015

あなたが尋ねたことを実行するための実際に実行可能な方法はありません。
DopeGhoti

1
表示された値が静的である場合は実行可能です(OPの質問ではそれが許可されていないようです)。シェル変数に前回のエポック時間を保存することにより、経過時間を維持できます。それを実装することは大変な作業のようですが(1時間程度-おそらく誰かが私が考えているよりも簡単な解決策を提供してくれるでしょう)。 この質問は役に立ちます。
Thomas Dickey、2015

回答:


10

これを行う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.2echo $BASH_VERSION)以降dateでは、新しいprintfフォーマット文字列を使用した外部呼び出しを回避できます。$(date +%s)ピースをと交換し$(printf '%(%s)T' -1)ます。バージョン4.3以降では、-1パラメーターを省略して、「引数なしはすぐに」という動作に依存することができます。


これは本当に近いです。bashプロンプトからコピー/貼り付けすると機能しますが、.bashrcに追加しようとすると、「1451424431:コマンドが見つかりません」と出力されます
TeasingDart

多分少し多すぎてコピー/貼り付けましたか?
ジェフシャラー

この最後のバージョンは、私が望んでいたとおりに機能しました!私は、プロンプトの後にテキストの色を設定するという私のトラップと関係があると思います。ありがとうございました。
TeasingDart

リセットする$SECONDSと、シェルが起動してからの時間を追跡しなくなります
mikeserv

1
@chepner-確かに、しかしそれは二度とシェルの時間を保つことはありません。誤解しないでください。これは良い答えなので、私はこれに賛成しましたが$SECONDS、すべてのプロンプトに対して対話型シェルを再定義すると、予期しない動作が発生する可能性が高いと思います。ランタイムの評価に関連する何らかの理由でそれを使用する可能性がある他のシェル関数は、正しく動作しません。
mikeserv 2015

4
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]ながら常に正しい値を設定する方法で自己再帰的であることを定義します。この部分を取得するには、シェル数学式が評価される順序を考慮する必要があります。最も重要なことは、shell-mathは常にshell-mathの最後の業務です。何よりもまず、シェルは値を展開します。このようにして、を使用して割り当てた後、数式でシェル変数の古い値を参照できます$

最初に簡単な例を示します。

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

40 15

シェルは、最初にドル記号参照が使用されている$x場所の値を代入することによってそのステートメントを評価します。$したがって、式は次のようになります。

(x+=5)+10+x

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

これは$PS1、配列インデックスで利用される数学の拡張/評価のレベルがさらにあることを除いて、主に方程式が機能する方法です。

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

なぜ私PS1[1]=!1がそこで使用することを選んだのか本当にわかりません-それはおそらくばかげた美学だったと思います-しかし、これ$PS1[1]はパラメータ置換のためにそれを拡張している間0を割り当てます。0とそれ以外のビット単位のANDの値は常に0になりますが&&、左端のプライマリが0の場合はブール値のように短絡しないため、括弧付きの式は毎回評価されます。もちろん、その最初の省略記号はの初期値$PS1[2,3]が設定される場所であるため、これは重要です。

とにかく、$PS1[1]プロンプト描画の間に改ざんされたとしても、ここでは0になることが保証されています。括弧内に...

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

... $PS1[2]の違いに割り当てられている$PS1[3]とする$SECONDSと、$PS1[3]その値の商を割り当てられ、3600のすべての値は、ここで初期化されます。など:

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

... $PS1[3]内部に2桁以上ある場合、内部展開はnull $PS1[1]です。0であることがわかっている$PS1[3]ので、何も代入されない場合は置き換えられ、それ$PS1[1]以外の場合もその値に展開されます。このようにして、$PS1[3]割り当ての反復ごとに1桁の値だけが先行ゼロを展開し、$PS1[3]それ自体が直後に60を法として展開され、同時に時間、分、秒ごとに次の連続的に小さい値が同時に割り当てられます。

プロンプトが次に表示されたときにもう一度比較できるように$PS1[3]、現在の値で上書きされる最後の反復まですすぎ、繰り返します。$SECONDS$SECONDS


1

これまでに見つけた最良の解決策はこれです:https : //github.com/jichu4n/bash-command-timer

これ[ 1s011 | May 25 15:33:44 BST ]は、実行されたコマンドの後に右側に経過時間を表示するので、PS1が煩雑になることはありません。

文字列と時刻の形式全体を構成できます。色や精度も設定可能です。ミニマリストにとっては少々多いかもしれませんが、それはかなりクールです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.