はじめに
PROMPT_COMMAND とは
PROMPT_COMMAND に関数やコマンドがセットされていると、Bash でプロンプトを表示する直前に、毎回それが実行されます。
この機能を利用して PS1 を動的に書き換える例を見かけることがあります。
PS1 内でコマンドの出力を表示する
しかし、PS1 内でも関数やコマンドを実行して、結果の文字列を表示することができます。1
ただ、うろ覚えでこの辺りの設定をしていたところ、少々ハマってしまったので、実際に自分が間違えた例と合わせて、正しい設定方法を記しておきます。
よく使われる git-completion を題材に用います。
※以降の例で、git-prompt.sh
相当のものは読み込み済みとします。
間違い例1
# ~/.bashrc
__my_ps1() {
local branch=$(__git_ps1)
[[ $branch ]] && branch="\[\e[0;35m\]$branch\[\e[0m\] "
echo "[${branch}\u@\h:\W] "
}
PS1="$(__my_ps1)"
一見ちゃんと動きそうで、実際動きはするのですが、PS1 の文字列は最初にこのスクリプトを評価したときのままで、ディレクトリを移動しても、__my_ps1
関数が再評価されることはありません。
実行例:
[me@localhost:~] cd path/to/gitrepo
[me@localhost:gitrepo] # branch は表示されない
[me@localhost:gitrepo] . ~/.bashrc # 再読み込み
[ (master) me@localhost:gitrepo] # 表示される
[ (master) me@localhost:gitrepo] cd
[ (master) me@localhost:~] # 非gitディレクトリでも表示されてしまう
(例では、カラーコードは反映されていません。)
間違い例2
# ~/.bashrc
__my_ps1() {
local branch=$(__git_ps1)
[[ $branch ]] && branch="\[\e[0;35m\]$branch\[\e[0m\] "
echo "[${branch}\u@\h:\W] "
}
PS1='$(__my_ps1)'
この場合、__my_ps1
関数は毎回実行・評価されてくれるのですが、エスケープシーケンスが評価されず、文字列としてそのまま表示されてしまいます。
実行例:
[\u@\h:\W] cd path/to/gitrepo
[\[\e[0;35m\] (master)\[\e[0m\] \u@\h:\W] # branch は表示される
[\[\e[0;35m\] (master)\[\e[0m\] \u@\h:\W] cd
[\u@\h:\W] # branch は表示されない
なんとも残念な見た目ですorz
正しい例
正しくは、下のように PS1
内で $(関数 or コマンド)
をシングルクォートで記述します。
# ~/.bashrc
PS1='[\[\e[0;35m\]$(__git_ps1)\[\e[0m\] \u@\h:\W] '
ダブルクォートで括りたい場合は、 "\$(__git_ps1)"
のようにエスケープすれば OK です。
実行例:
[me@localhost:~] cd path/to/gitrepo
[ (master) me@localhost:gitrepo] # branch は表示されない
以上です。
参考になれば幸いです。
参考
- Bash Reference Manual#Controlling-the-Prompt
- PS1とPROMPT_COMMAND, GNU screenでの活用も
- 「Git補完をしらない」「git statusを1日100回は使う」そんなあなたに朗報【git-completionとgit-prompt】 - Qiita
-
余談ですが、筆者は PROMPT_COMMAND で PS1 を書き換えて先輩に注意を受けたことがあります。 ↩