ターミナルのタブを複数開けて、異なるプロジェクトを同時並行で作業することがあった。それで主に下記の2点が不便だったので、なんとかできんかなーと思い色々やってみた。
解決したい課題
- ターミナル / IDE / エディタ等を行き来すると、どのタブがどのプロジェクトを開いているのか、パッと見てすぐに分からないので、すぐに分かるようにしたい
- それぞれのタブで打ったコマンドの履歴が独立していて、
↑
ボタンで思ったコマンドがでないのでなんとかしたい
1. 任意のディレクトでプロンプトの色を変更する
-
PROMPT_COMMAND
というシェル変数があり、この値に設定したコマンドや関数はプロンプトの表示前に実行される - このシェル変数で、任意のディレクトに移動後、プロンプトの色を変更して、どのプロジェクトを開いてるのか色で分かるようにする
- 次の
prompt_command_color
は特定のディレクトリに移動すると、プロンプトに表示するGitのブランチ名だけ色を変更する関数です
.bash_profie
# Gitのbranchを表示
source /usr/local/etc/bash_completion.d/git-prompt.sh
source /usr/local/etc/bash_completion.d/git-completion.bash
GIT_PS1_SHOWDIRTYSTATE=true
GIT_PS1_SHOWSTASHSTATE=true
GIT_PS1_SHOWUPSTREAM=auto
# Gitのブランチ名を色付きで表示
function prompt_command_color () {
CURRENT=$(basename `pwd`)
if [ "$CURRENT" = 'directory1' ]; then
export PS1='\[\e[0;36m\][\u@\h \W]\$\[\e[0m\]\[\033[01;33m\]$(__git_ps1 [%s])\[\033[00m\]\$ '
elif [ "$CURRENT" = 'directory2' ]; then
export PS1='\[\e[0;36m\][\u@\h \W]\$\[\e[0m\]\[\033[01;38m\]$(__git_ps1 [%s])\[\033[00m\]\$ '
else
export PS1='\[\e[0;36m\][\u@\h \W]\$\[\e[0m\]\[\033[01;32m\]$(__git_ps1 [%s])\[\033[00m\]\$ '
fi
}
PROMPT_COMMAND=prompt_command_color
2. コマンド履歴の共有
.bash_profie
# コマンド履歴の共有
function prompt_command_sync_history () {
history -a # .bash_historyに前回コマンドを1行追記
history -c # 端末ローカルの履歴を一旦消去
history -r # .bash_historyから履歴を読み込み直す
}
shopt -s histappend # .bash_history追記モードは不要なのでOFFに
HISTCONTROL=ignoreboth # コマンドの重複を防ぐ
PROMPT_COMMAND=prompt_command_sync_history
1. と2. の関数を PROMPT_COMMAND
ヘ同時に設定する
一つの関数でまとめてやればすぐにできる。でも、機能追加するたびに行が長くなるし、同じ関数で別々の処理が走るので辛い。
処理ごとに関数を分けて PROMPT_COMMAND
に設定したい。でも、複数の関数を一つのシェル変数に設定する方法が分からずハマる。
- 下記の記事で出来た助かった
http://qiita.com/tay07212/items/9509aef6dc3bffa7dd0c
.bash_profie
# 色を変更する関数と、履歴共有の関数をグローバルな変数に入れる
PROMPT_COMMAND_COLOR=prompt_command_color
PROMPT_COMMAND_SYNC_HISTORY=prompt_command_sync_history
# PROMPT_COMMANDに複数の関数を割り当てる関数
function dispatch () {
for f in ${!PROMPT_COMMAND_*}; do # ${!HOGE*}は、HOGEで始まる変数の一覧を得る
eval ${!f} # ${!f}は、$fに格納された文字列を名前とする変数を参照する(間接参照・間接展開)
done
}
PROMPT_COMMAND=dispatch
こんな感じになる
-
PROMPT_COMMAND
はプロンプトの表示前に実行されるので enter 押せば、コマンド履歴は共有される
番外編1 : ${!f} がよくわからん
- 間接参照とか間接展開とか呼ばれてるぽい
http://kodama.fubuki.info/wiki/wiki.cgi/bash/tips?lang=jp
例1
$ A=BBB
$ BBB=1
$ echo ${A}
BBB
$ echo ${!A} # これは eval echo \$$A や eval echo '$'$A と 同じ
1
番外編2 : eval echo $$A や eval echo '$'$A と 同じ?
例2
$ A=BBB
$ BBB=1
$ echo $A
BBB
$ echo \$A
$A
$ echo $$A # $$はプロセスID(51856)
51856A
$ echo \$$A
$BBB
$ eval echo \$$A
1
$ eval echo '$'$A
1
- 要するに、 上記で自作した
dispatch
という関数で実行しているeval ${!f}
は、fの中にある文字列を変数として展開すると、中身が関数だったので、その関数をevalが実行するということだった。
まとめ
- いろいろ画面を行き来しても、色でパッと見分けられ、コマンドも共有でき、快適になりました
- bashは理解するのが大変だったけど、なんか妙に引き込まれる魅力がある
- bash力が少し上がった