Bash:終了ステータスをプロンプトに表示します:


11
GREEN="\e[1;32m"
RED="\e[1;31m"
NONE="\e[m"

get_exit_status(){
   es=$?
   if [ $es -eq 0 ]
   then
       echo -e "${GREEN}${es}${NONE}"
   else
       echo -e "${RED}${es}${NONE}"
   fi
}

get_path(){
    #dummy function
    echo "PATH"
}

PROMPT_COMMAND='exitStatus=$(get_exit_status)'

以下は正しいexitStatusを私に与えますが、色変数は展開されません:

PS1='${RED}\h $(get_path) ${exitStatus}${NONE} '

ただし、以下のものは色を提供しますが、終了ステータスは更新されません。

PS1="${RED}\h $(get_path) ${exitStatus}${NONE} "

これを行う正しい方法は何ですか?exitStatusと色の両方が機能するようにこれを修正するにはどうすればよいですか?

回答:


8

Gillesがあなたの主な問題を特定しましたが、別の方法で説明してみました。

Bash は、プロンプト内の変数を展開する前にのみ、特別なプロンプトエスケープを解釈します。つまり、プロンプトで直接展開された変数での使用は、で直接機能しても機能しません。\ePS1

たとえば、これは期待どおりに機能し、赤いテキストが表示されます。

PS1='\e[1;31m this is in red '

しかし、これはそうではなく、\eプロンプトにリテラルを置くだけです:

RED='\e[1;31m'
PS1="$RED not in red "

変数にカラーエスケープを格納する場合は、ANSI-C引用符($'...')を使用して、リテラルエスケープ文字を変数に入れることができます。

これを行うには、あなたはあなたの定義を変更することができGREENREDおよびNONE、その価値は、実際のエスケープシーケンスです。

GREEN=$'\033[1;32m'
RED=$'\033[1;31m'
NONE=$'\033[m'

これを行うPS1と、単一引用符を使用した最初のものが機能するはずです。

PS1='${RED}\h $(get_path) ${exitStatus}${NONE} '

ただし、その場合は2番目の問題が発生します。

それを実行してみてください、そしてEnterキーを押してUp Arrow、それからHome、あなたのカーソルが行の先頭に戻って行くことはありません。

それを修正するには、変更がPS1含まれるように\[して\]カラーエスケープシーケンスの周りに、例えば

PS1='\[${RED}\]\h $(get_path) $?\[${NONE}\] '

get_exit_status出力には印刷(終了コード)と非印刷文字(カラーコード)の両方が含まれており、プロンプトで正しくマークする方法がないため、ここでは適切に使用できません。パッティング\[...\]すると、完全に非印刷としてマークされますが、これは正しくありません。関数を変更して適切なカラーコードのみを印刷\[...\]し、プロンプトで囲む必要があります。


\[であり\1\[です\2。これらはRL_PROMPT_{START,END}_IGNORE、画面上のプロンプトの長さを数えるときにバイトを無視するように求めるreadlineのものに対応しています。list.gnu.org/archive/html/bug-bash/2015-08/msg00027.htmlを参照してください。
Arthur2e5 2015年

@ Arthur2e5ということ\]です\2か?そして、それが理由で必要なの${exitStatus}ですか?私のポイントは、ということでした${exitStatus}bashが正しく、それはせずにプロンプトを動かすどのように多くの文字を決定することができるはずですので、非印刷文字が含まれていない\[\]して\[${exitStatus}\]
ミケル

問題は、色が含まれていることです。(ANSI Escapes)
Arthur2e5 2015年

@ Arthur2e5 Ew、私は完全にそれを逃した。:)なぜあなたは色を置くでしょう...気にしないでください。:)
ミケル

1
「Bashは効果的に、echo -eではなく、PS1でechoを呼び出しています」 -それはまちがっている、または単に要点がありません。バッシュは、バックスラッシュ・エスケープのような拡張しない\e\033(および\[/ \]\u、および\hプロンプトから)、それだけでそうする前に、変数を展開します。ですからPS1='\e[1;31m red'、働くred='\e[1;31m'; PS1='$red red'ません。
ilkkachu 2018

3

を実行するPS1='${RED}\h $(get_path) ${exitStatus}${NONE} 'と、PS1変数はに設定されます。${RED}\h $(get_path) ${exitStatus}${NONE}ここ\hで、プロンプトエスケープシーケンスのみです。プロンプト配列が展開され(得${RED}darkstar $(get_path) ${exitStatus}${NONE})、シェルは、可変膨張などの通常の展開を行います。のようなプロンプトが表示されます\e[1;31mdarkstar PATH 0\e[m。途中で\eシーケンスを実際のエスケープ文字に拡張するものはありません。

を実行するPS1="${RED}\h $(get_path) ${exitStatus}${NONE} "と、PS1変数はに設定され\e[1;31m\h PATH 0\e[mます。変数REDexitStatusおよびNONEは、割り当て時に展開されます。その後、プロンプトが3つのプロンプトのエスケープシーケンスが含まれています(\e\h、および\e再び)。この段階で展開するシェル変数はありません。

色を表示するには、実際のエスケープ文字を含む色変数が必要です。あなたはこの方法でそれを行うことができます:

RED=$'\033[1;31m'
NONE=$'\033[m'
PS1='\[${RED}\]\h \w $?\[${NONE}\] '

$'…'バックスラッシュ-8進数シーケンスと、などのバックスラッシュ文字シーケンスを展開します\nが、は含みません\e。プロンプトに他に3つの変更を加えました。

  • \[…\]色変更コマンドなどの非印刷シーケンスを中心に使用します。そうしないと、bashがプロンプトの幅を理解できないため、ディスプレイが文字化けしてしまいます。
  • \w 現在のディレクトリを出力するための組み込みのエスケープシーケンスです。
  • そもそもがない場合$?は、プロンプトに複雑なものを表示する必要はありませんPROMPT_COMMAND

成功した場合はプロンプトを緑色に、失敗した場合はプロンプトを赤色にするという考えだったと思います。
mattdm 2011

はい、PS1間違っているが、使用に助言$'...'のためにREDGREEN、それはdogbaneのを使用して動作させる必要がありますPS1
ミケル

1

試してください:

PS1='`exitStatus=$?;if [ $exitStatus -eq 0 ];then echo "\['${GREEN}'\]";else echo "\['${RED}'\]";fi;echo "\h $(get_path) ${exitStatus}${NONE}"`'

1
ありがとう、これは機能しますが、プロンプト内にifステートメントを埋め込むことなくこれを達成する方法はありますか?
dogbane 2011年

1

ここに私が行ったアプローチがあります、それはの使用を避けますPROMPT_COMMAND

# This function is called from a subshell in $PS1,
# to provide a colourised visual indicator of the exit status of the last run command
__COLOURISE_EXIT_STATUS() {
    # uncomment the next line for exit code output after each command, useful for debugging and testing
    #printf -- "\nexit code: $1\n" >&2
    [[ 0 == "$1" || 130 == "$1" ]] && printf -- "$GREEN" || printf -- "$RED"
}

それから私$PS1は次のとおりです:

PS1='# ${debian_chroot:+($debian_chroot)}'"${GREEN}\u${YELLOW}@${DARK_YELLOW}\h${WHITE}:${LIGHT_BLUE}\w${WHITE}\n"'\[$(__COLOURISE_EXIT_STATUS $?)\]# \$'"\[${WHITE}\] "

1
この特定のケースでは問題ではありませんが、唯一の値$?は整数であるため、実際にはprintf '%b' "$GREEN"代わりに使用する必要があります。また、関数名の使用を避けるには、接頭辞__または_彼らはbashの補完によって使用されているよう。
nyuszika7h 14年

1

ここに行きます -これはUbuntuと他のLinuxes(Linuxen?)で動作します(TM)。

終了コードを検出する理由$PS1は、1つのホスト$PROMPT_COMMANDに.bashrcが読み取られる前に読み取り専用のセットが設定されているためです。


0

の場合PROMPT_COMMANDは、関数を定義してそれを使用する方が簡単です。

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