Bash/プロンプトのカスタマイズ
関連記事
Bash には複数のプロンプトが存在しカスタマイズすることで効率を高めたりセンスを良くしたりオタクっぽくできます。
目次
プロンプト
Bash にはカスタマイズ可能な5つのプロンプト文字列が存在します:
PS0
は、コマンドの入力が完了した後で、そのコマンドの出力が開始される前に表示されます。(つまり、コマンドの実行開始直前。)PS1
は、コマンドの入力が開始される前に表示されるプライマリプロンプトです。なので、ほとんどの人がカスタマイズするのはこのプロンプト文字列です。PS2
は、コマンドにさらに多くの入力 (例えば複数行のコマンド) が必要とされる際に表示されるセカンダリプロンプトです。PS3
は滅多に使われません。これは、Bash のselect
組み込みコマンドによってインタラクティブメニューが表示されるときに使われるプロンプト文字列です。他のプロンプトと違って、このプロンプトでは Bash のエスケープシーケンスを展開することはできません。通常、このプロンプトは.bashrc
ではなく、select
が使用されているスクリプト内でカスタマイズします。PS4
も滅多に使われません。Bash スクリプトをデバッグする際に間接参照のレベルを表示するために使われます。最初の文字が繰り返されて、レベルの深さを表します。
全てのプロンプトは、それぞれに対応する変数を設定することでカスタマイズできます (大抵は ~/.bashrc
で設定します)。例えば:
PS2='> '
テクニック
プロンプトを普通の文字列に設定することもできますが、様々なテクニックを駆使することでプロンプトをもっとダイナミックに使いやすくすることができます。
Bash のエスケープシーケンス
プロンプトの文字列を表示するとき、Bash はバックスラッシュでエスケープされた特定の文字列を探し、特殊な文字列に展開します。例えば \u
は現在のユーザー名になり \A
は現在時刻になります。PS1 を '\A \u $ '
と設定すると 17:35 username $
といった具合に表示されます。
エスケープシーケンスの完全なリストは、bash(1) § PROMPTING man ページか Bash リファレンスマニュアルを参照してください。
Terminfo のエスケープシーケンス
Bash によって認識されるエスケープシーケンスの他に、大抵のターミナルは特殊なエスケープシーケンスを認識して表示される文字列だけでなくターミナル自体に変化を起こします。例えば、表示される文字列の色を変更したり、カーソルを任意の場所に移動したり、画面を消去したりすることができます。そのようなエスケープシーケンスは人間が読むことができない形で表記され、ターミナルによって違うこともあります。terminfo データベースでドキュメント化されています。ターミナルがサポートしている機能を確認するには、次のコマンドを実行:
$ infocmp
機能の名前 (= よりも前の部分) は terminfo(5) の man ページを読めば何なのか説明を見ることができます。例えば setaf
は出力されるテキストの前景色を設定します。特定の機能のエスケープシーケンスを確認するには、tput
コマンドを使います。例:
$ tput setaf 2
上記のコマンドは前景色を緑に設定するエスケープシーケンスを表示します。
使用できる機能をプロンプトに組み込むときは、Bash のコマンド置換と補完機能を使用できます。例:
~/.bashrc
GREEN="\[$(tput setaf 2)\]" RESET="\[$(tput sgr0)\]" export PS1="${GREEN}my prompt${RESET}> "
ANSI のエスケープシーケンス
残念がら、ANSI のエスケープシーケンスはターミナルの terminfo データベースには載っていないことがあります。特に256色のサポートなど新しい機能のエスケープシーケンスはデータベースに入っていないことがよくあります。tput を使えない場合、エスケープシーケンスを手動で入力する必要があります。
エスケープシーケンスの例は Wikipedia:ANSI escape code を見てください。全てのエスケープシーケンスはリテラルのエスケープ文字から始まり Bash のエスケープシーケンス \e
を使って入力できます。例えば \e[48;5;209m
は背景を桃色 (ターミナルが256色をサポートしている場合) に設定し、\e[2;2H
はカーソルを画面左上に移動します。
Bash のエスケープシーケンスがサポートされていない場合 (PS3 など)、Bash の printf を使うことでリテラルのエスケープ文字を使用できます:
ESC=$(printf "\e") PEACH="$ESC[48;5;209m"
コマンドの埋め込み
何かコマンドの出力をプロンプトに追加したい場合、コマンド置換を使えばいいと思うかもしれません。例えば、空きメモリ容量をプロンプトに追加しようと以下のように設定した場合:
export PS1="$(awk '/MemFree/{print $2}' /proc/meminfo) prompt > "
53718 prompt > 53718 prompt > 53718 prompt >
上記の設定は上手くいきません。表示されるメモリの容量はいつも同じになってしまいます。原因はコマンドの実行が一回しか行われず、PS1 が一度設定されると、二度と変わらないためです。$
をエスケープするかシングルクォートの中で定義するようにすることで、プロンプトが実際に表示されるときにコマンド置換がされるようになります:
export PS1="\$(awk '/MemFree/{print \$2}' /proc/meminfo) prompt > " # or export PS1='$(awk "/MemFree/{print \$2}" /proc/meminfo) prompt > '
コマンドが長い場合は、関数を定義することで PS1 の肥大化を抑えられます:
free_mem() { awk '/MemFree/{print $2}' /proc/meminfo } export PS1='$(free_mem) prompt > '
PROMPT_COMMAND
PROMPT_COMMAND
変数を設定することで、PS1 が表示される直前に評価することができます。非常に強力な使い方ができます。例えば特定の条件で PS1 を再定義したり、コマンドを実行したときに Bash の履歴に何らかの操作を加えたりできます。
コマンドの入力完了と実行開始の間でエスケープシーケンス
PS1 の末尾でテキストのプロパティをリセットせずにそのままにしておくことで、Bash に入力したテキストにもそのプロパティを反映させることができます。例えば、PS1 の最後に tput blink
を追加すると、入力されたコマンドが点滅します。ただし、エンターを押してもテキストのプロパティはリセットされないため、実行されたコマンドの出力にも影響が及びます。
PS0 にエスケープシーケンスを設定することで、コマンドを入力した後、かつそのコマンドが実行される前にそのエスケープシーケンスを挿入することができます。あるいは、コマンドが実行される直前に送信される Bash の DEBUG シグナルを捕捉することで、同じことをすることができます:
$ trap 'tput sgr0' DEBUG
root プロンプトのカスタマイズ
root で実行していることを知らせるために、root プロンプトはわかりやすいようにカスタマイズすると良いでしょう (赤字の点滅など)。root のホームディレクトリ (/root
) を使うことで通常の Bash プロンプトのカスタマイズと同じようにカスタマイズできます。最初にスケルトンファイルの /etc/skel/.bash_profile
と /etc/skel/.bashrc
を /root
にコピーしてから /root/.bashrc
を編集してください。
サンプル
色
ターミナルでサポートされている色の完全な範囲は、tput を単純なループで回すことで確認できます (背景色ではなく前景色で表示するには setab
を setaf
に置き換えてください)。
for C in {0..255}; do tput setab $C echo -n "$C " done tput sgr0 echo
上記のコマンドが動かない場合 (そして、TERM に適切な値を設定しても問題が解決できない場合)、別のエスケープシーケンスでテストすることもできます:
# 標準色 for C in {40..47}; do echo -en "\e[${C}m$C " done # 高輝度色 for C in {100..107}; do echo -en "\e[${C}m$C " done # 256色 for C in {16..255}; do echo -en "\e[48;5;${C}m$C " done echo -e "\e(B\e[m"
エスケープシーケンスを背景色から前景色に変更したい場合は、標準色の範囲を 30..37
に、高輝度色の範囲を 90..97
にし、256色ではエスケープシーケンスの 48
の部分を 38
に変更してください。
一般的な機能
以下の terminfo の機能はプロンプトをカスタマイズするときに使うことができ多くのターミナルがサポートしています。#1 や #2 は実際に使うときに数字に置き換えてください。
機能 | エスケープシーケンス | 説明 |
---|---|---|
テキストの属性 | ||
blink | \e[5m | テキストの点滅をオン |
bold | \e[1m | 太字テキストをオン |
dim | \e[2m | 淡色テキストをオン |
rev | \e[7m | 逆転表示をオン (前景色と背景色が入れ替わります) |
sitm | \e[3m | 斜字テキストをオン |
ritm | \e[23m | 斜字テキストをオフ |
smso | \e[7m | テキストのハイライトをオン |
rmso | \e[27m | テキストのハイライトをオフ |
smul | \e[4m | テキストの下線をオン |
rmul | \e[24m | テキストの下線をオフ |
setab #1 | \e[4#1m | 背景色を #1 (0-7) に設定 |
setaf #1 | \e[3#1m | テキスト色を #1 (0-7) に設定 |
sgr0 | \e(B\e[m | テキストの属性をリセット |
カーソルの移動 | ||
sc | \e7 | カーソルの位置を保存 |
rc | \e8 | 保存したカーソルの位置に戻す |
clear | \e[H\e[2J | 画面をクリアし、カーソルを左上に移動 |
cuu #1 | \e[#1A | #1 行分だけカーソルを上に移動 |
cud #1 | \e[#1B | #1 行分だけカーソルを下に移動 |
cuf #1 | \e[#1C | #1 列分だけカーソルを右に移動 |
cub #1 | \e[#1D | #1 列分だけカーソルを左に移動 |
home | \e[H | カーソルを左上に移動 |
hpa #1 | \e[#1G | カーソルを #1 列目に移動 |
vpa #1 | \e[#1d | カーソルを #1 行目の1列目に移動 |
cup #1 #2 | \e[#1;#2H | カーソルを #1 行目の #2 列目に移動 |
文字列の削除 | ||
dch #1 | \e#1P | (バックスペースと同じように) 文字を #1 個削除 |
dl #1 | \e#1M | 行を #1 個削除 |
ech #1 | \e#1X | 文字を #1 個消去 (カーソルの移動は伴わない) |
ed | \eE[J | 画面下端まで消去 |
el | \e[K | 行末まで消去 |
el1 | \e[1K | 行頭まで消去 |
終了コードの視覚化
コマンドの埋め込みと同じ方法で $?
などの特殊な Bash 変数の補完を遅延させることができます。以下のプロンプトは前に実行したコマンドの終了コードを表示します:
PS1="\$? > " # または PS1='$? > '
0 > false
1 >
条件式と関数を使うことでさらにわかりやすくすることができます:
exitstatus() { if [[ $? == 0 ]]; then echo ':)' else echo 'D:' fi } PS1='$(exitstatus) > '
:) > false
D: >
カーソルの位置
PS1 の中でカーソルを移動することで、プロンプトをパーツに分けてそれぞれを別々の場所に表示させることができます。しかし、カーソルと出力を正しい位置に表示させるために、プロンプトの表示が終わったらカーソルを元の場所に戻さなければなりません。tput の sc
と rc
という機能を使うことでカーソルの位置を保存して後で戻すことができます。カーソルを移動するプロンプトは、一般に以下のようになります:
PS1="\[$(tput sc; カーソル移動のコード) 移動されたプロンプト $(tput rc)\] 通常のプロンプト"
移動されたプロンプトは、Bash によって通常のプロンプトの一部として認識されないようにするために、\[ \]
内に記述します。
テキストを右寄せ
テキストを右寄せで表示させる最も単純な方法は、printf を使うことです:
rightprompt() { printf "%*s" $COLUMNS "right prompt" } PS1='\[$(tput sc; rightprompt; tput rc)\]left prompt > '
上記のコードは、右寄せの可変長フィールド %*s
を作成し、ターミナルの現在の列数 $COLUMNS
に対して文字列のサイズを設定します。
任意の位置
cup
機能では画面の特定の位置にカーソルを移動できます。例えば tput cup 20 5
は20行目5列目にカーソルを移動します (0行目0列目が左上です)。cuu
, cud
, cuf
, cub
(上, 下, 右, 左) は現在の位置から相対的にカーソルを移動します。例えば tput cuf 10
はカーソルを10文字分だけ右に移動します。引数で LINES
と COLUMNS
変数を使うことで下端と右端からの相対位置にカーソルを移動できます。例えば、右下から10行目5列目にカーソルを移動するには:
$ tput cup $((LINES - 11)) $((COLUMNS - 6))
ターミナルのウィンドウタイトルのカスタマイズ
プロンプトと同じ方法 (シェルにエスケープシーケンスを出力する) で、ターミナルのウィンドウタイトルをカスタマイすできます。なので、プロンプト内にウィンドウタイトルをカスタマイズするコードを含めるのは一般的です。これは技術で器には xterm の機能ですが、最近のターミナルの多くはこの機能をサポートしています。使用するエスケープシーケンスは ESC]2;new titleBEL
です。ここで、ESC
と BEL
はそれぞれエスケープ文字とベル文字です。Bash のエスケープシーケンスを使えば、以下のようにしてプロンプト内でタイトルを変更できます:
PS1='\[\e]2;タイトル\a\]prompt > '
もちろん、ウィンドウタイトルの文字列にはコマンドの出力結果や $PWD
などの変数を含めることができ、プロンプトが表示されるたびにタイトルを変化させることができます。
参照
- Arch フォーラムのスレッドに投稿されたコミュニティの作例とスクリーンショット: What's your PS1? (ログインした場合にのみ閲覧可)
- Gentoo の /etc/bash/bashrc。gentoo-bashrcAUR も参照。
- tput(1)
- Bash Prompt HOWTO
- Giles Orr1 のプロンプトコレクション
- Bash ヒント: カラー出力とフォーマット
- Liquid Prompt — Bash & zsh 用の便利なアダプティブプロンプト
- Bash POWER PROMPT
- Wikipedia:ANSI escape code
- GNU Bash manual: プロンプトの制御