SlideShare a Scribd company logo
Zshでデキるプロンプト
まるやま
2013/05/10
1 / 25
プロンプトをいじりたい
人生、色々あるよね
仕事に疲れた…
育児に疲れた…
贔屓のチームが負けた…
そもそも人生に疲れた…
そんな時は、デスクトップの見た目をいじりたくなるよね
みんなそうだよね!(Yes!)
ターミナルのプロンプトを変更したくなる時もあるよね
みんなそうだよね!(Yes!)
じゃあ、思い切りいじろうじゃないか!(Yeah!!)
2 / 25
Zshのプロンプトをいじるよ
みんな、シェルは Zsh だよね
そうじゃない人は、これを見て Zsh に変更するもよし
apt-get install zsh && chsh で /bin/zsh に!
Zsh は意外とステキだよ
補完が何かとすごい
履歴も何かとすごい
プロンプトもいじり甲斐があるのさ
改行を入れて複数行のプロンプトが可能
右プロンプトがある
Zsh の設定項目はいっぱいあって正直とっつきにくいけど、
今回はプロンプトの設定だけに絞って紹介するよ!
Zsh のバージョンによって対応してなかったりとかあるけど、
最新バージョン(2013/05/10 現在、4.3.17)を前提とするよ
3 / 25
プロンプトに何を出そうか
プロンプトに出せる情報は、意外といっぱいある
man zshmisc の”SIMPLE PROMPT ESCAPES” を参照
プロンプトのイメージ
[現在のディレクトリ]
ユーザー名@マシン名 マーク (ここに入力...)
ポイント
複数行が出来るから、1行目にディレクトリ名を表示
ディレクトリ名は青色太文字で
ディレクトリ名を1行目に追いやったので、
肝心のプロンプト部はユーザー名&マシン名でスッキリ
4 / 25
プロンプトその1
~/.zshrc
autoload colors
colors
local p cdir="%B%F{blue}[%~]%f%b"$’n’
local p info="%n@%m"
PROMPT=" $p cdir$p info > "
5 / 25
プロンプトその1の解説
autoload colors と colors 色を出力できるようにする
%B…%b %B と%b の間の文字を太字にする
%F{color}…%f %F と%f の間の文字を color 色にする
%˜ カレントディレクトリ(ホームは “˜”)を出力
$’n’ 改行
%n ユーザー名
%m ホスト名
local 普通に変数を定義すると環境変数として見えてしま
うが、local をつければ見えない
PROMPT この変数に値を設定すれば、プロンプトとして表示
される
詳しい内容その他は、man zshmisc を参照のこと
6 / 25
ユーザーIDでマークを変更
マークは太字にしよう
通常のユーザーの場合は、マークとして “>” を使いたい
root の場合は、きちんと区別するため “#” を使いたい
~/.zshrc
local p cdir="%B%F{blue}[%~]%f%b"$’n’
local p info="%n@%m"
local p mark="%B%(!,#,>)%b"
PROMPT=" $p cdir$p info $p mark "
colors は(以降も)省略
%( , , ) は if...then...else...
!は(ここでは)
特権ユーザーの判定
詳しくはやはり
man zshmisc で
7 / 25
コマンドの返り値で色を変化
直前のコマンドが成功している場合はマークを緑に
コマンドがエラーの場合は、マークを赤に
~/.zshrc
local p cdir="%B%F{blue}[%~]%f%b"$’n’
local p info="%n@%m"
local p mark="%B%(?,%F{green},%F{red})%(!,#,>)%f%b"
PROMPT=" $p cdir$p info $p mark "
?は(この場合は)直前のコマンドの返り値
%( , , ) を使って、色の指定を変えているだけ
8 / 25
スクリーン番号を(あれば)表示
screen コマンドなどで仮想ターミナルを使っている場合は、
ウィンドウ番号を(“[ ]” の中に)表示したい
使っていない場合は、何も表示したくない
~/.zshrc
local p cdir="%B%F{blue}[%~]%f%b"$’n’
local p info="%n@%m${WINDOW:+"[$WINDOW]"}"
local p mark="%B%(?,%F{green},%F{red})%(!,#,>)%f%b"
PROMPT=" $p cdir$p info $p mark "
${HOGE:+text} は、変数 HOGE が定義されていて値がある
場合のみ、変数 HOGE の値を text に置換する
詳しくは man zshexpn
$WINDOW は、仮想ターミナルのウィンドウ番号が(あれ
ば)格納される変数
9 / 25
スクリーン番号を(あれば)表示
下にスクリーン番号とウィンドウ名の一覧が出ているのは、
screen の設定
10 / 25
リモートホスト名の表示
ssh などで他のマシンに入っている場合は、
混乱するといけないので、元のマシン名を表示したい
元のマシン名は FQDN でなく(%m のように)簡単なのが
いい
Astec-X などの X サーバを使っている場合は、
(意外と重要なので)ディスプレイ番号を表示したい
…
さぁ、いよいよ難しくなってきた
オラ、ワクワクしてきたぞ(変態)
11 / 25
リモートホスト名の表示(続き)
~/.zshrc
local p rhst=""
if [[ -n "${REMOTEHOST}${SSH CONNECTION}" ]]; then
local rhost=‘who am i|sed ’s/.*((.*)).*/1/’‘
rhost=${rhost#localhost:}
rhost=${rhost%%.*}
p rhst="%B%F{yellow}($rhost)%f%b"
fi
local p cdir="%B%F{blue}[%~]%f%b"$’n’
local p info="%n@%m${WINDOW:+"[$WINDOW]"}"
local p mark="%B%(?,%F{green},%F{red})%(!,#,>)%f%b"
PROMPT=" $p cdir$p rhst$p info $p mark "
12 / 25
リモートホスト名の表示(解説)
rsh の場合は$REMOTEHOST にリモートホスト名が入ってる
ssh の場合は$SSH CONNECTION に接続先&元の IP アドレ
スとポート番号が入っている
連結して-n で中身を調べることで、両方に対応
その点、who am i は接続元をカッコの中に表示してくれる
それを sed で抜き出す(sed の説明は省略!)
X サーバの場合は、ここに “localhost:10.0” のような情報が
入っているので、“localhost:” を(あれば)削除
${HOGE#text} は、変数 HOGE の先頭から文字列 text を最
短マッチで探して削除
逆に${HOGE%%text} は、お尻から最長マッチで削除
ここらへんは man zshexpn
変な数字が表示されちゃう場合は、/etc/hosts をチェック
13 / 25
リモートホスト名の表示
Astec-X で接続した後に、色んな所に ssh で入った結果
14 / 25
PROMPT以外のプロンプト
以上で、PROMPT は満足(したとしよう)
でも、PROMPT 以外にも Zsh のプロンプトはあるよ
~/.zshrc(PROMPT2, SPROMPT)
PROMPT2="(% ) %(!,#,>) "
SPROMPT="correct: %R -> %r ? [n,y,a,e]: "
PROMPT2 if, for などで複数行に渡る場合のプロンプト
SPROMNT 入力したコマンドが存在しなく、「本当はこれ?」と
聞く場合のプロンプト
ま、これらは(私は)ほとんど使わないので、あまりこだわ
らないことにする
15 / 25
右プロンプト
重要なことを忘れていた
右プロンプト!
Zsh の白眉なんで、これを使わないと末代までの恥
でも、何を表示しよう
…
バージョン管理の状態を表示しよう!
16 / 25
vcs infoでgit情報を表示
偉い人はいるもので、git なら簡単に出来てしまう
~/.zshrc(git 情報を右プロンプトに)
autoload -Uz vcs info
zstyle ’:vcs info:*’ enable git
zstyle ’:vcs info:git:*’ check-for-changes true
function update vcs info msg() {
psvar=()
LANG=en US.UTF-8 vcs info
[[ -n "$vcs info msg 0 " ]] && psvar[1]="$vcs info msg 0 "
}
autoload -Uz add-zsh-hook
add-zsh-hook precmd update vcs info msg
RPROMPT="%1(v|%1v|)"
17 / 25
vcs infoでgit情報を表示(解説)
vcs info パッケージをロード
vcs info での情報取得に git を許可
git の状態チェックを許可
psvar=() で、psvar 変数(の配列)を初期化
psvar 変数配列は、%1v とか使えるので、とても便利
vcs info 関数を呼んで、情報取得
vcs info 関数は、$vcs info msg ? という変数に文字列をセッ
トするので、(デフォルトでは1個しか文字列が定義されて
いないので)もしもそれがあったら、psvar[1] にセット
add-zsh-hook パッケージをロード
プロンプトの表示前に update vcs info msg 関数を呼び出す
もしもセットされていたら、それを右プロンプトに表示
%1(v|hoge|moge) は、if %1v then hoge else moge
%1v で、実際の psvar[1] の値
詳しくは、man zshcontrib
18 / 25
しかし…cvs最高!
vcs info パッケージは、実質 git しか対応してない
hg や svn, bzr にも一部は対応してるが…
情報がいっぱい取れるのは git だけ
個人でソースを管理するには、cvs で十分!
簡単なこと、この上なし
git なんか使わないよ∼
でも vcs info は cvs の状態なんか全然表示してくれない
じゃあ、自分でやる!!
git なんかより、いっぱい情報出して、すんごく便利にしてや
るんだから!
19 / 25
表示したいcvsの情報と実装方針
普通に表示したい情報
VCS の情報(“cvs”)と、レポジトリ名
「注意」として黄色で表示したい情報
変更がローカルに反映されてない(“U”)ファイルの数
ローカルの変更がコミットされていない(“M”)ファイルの数
append されただけ(“A”)のファイルの数
remove されただけ(“R”)のファイルの数
レポジトリに何の情報もない(“?”)ファイルの数
「警告」として赤で表示したい情報
コンフリクトを起こしている(“C”)ファイルの数
実装方針
結局、最大3色で表示するので、本来ならば max-exports を設
定して、hook com で各変数(staged, unstaged)を変更すべき
ここらへんは「mollifier さんの Qiita ブログ」が非常に分かり
やす過ぎるので、説明省略
しかし、cvs だと全然上手くいかない(差別か?!)
仕方ないので、psvar 変数に直接アクセスする
20 / 25
右プロンプトにcvs状態表示・1
~/.zshrc(cvs 情報を右プロンプトに・1)
autoload -Uz vcs info
zstyle ’:vcs info:*’ enable git cvs
zstyle ’:vcs info:git:*’ check-for-changes true
zstyle ’:vcs info:cvs:*’ formats ’(%s)-[%r]’
zstyle ’:vcs info:cvs+set-messages:*’ hooks cvs-hook
function update vcs info msg() {
psvar=()
LANG=en US.UTF-8 vcs info
[[ -n "$vcs info msg 0 " ]] && psvar[1]="$vcs info msg 0 "
}
autoload -Uz add-zsh-hook
add-zsh-hook precmd update vcs info msg
RPROMPT="%1(v|%1v|)%2(v| %B%F{yellow}%2v%f%b|)"
"%3(v| %B%F{red}%3v%f%b|)"
21 / 25
右プロンプトにcvs状態表示・1(解説)
cvs も vcs info で有効に
メッセージの表示フォーマットを変更
%s, %r の意味などは、man zshcontrib
上記メッセージを作成する際に呼び出されるフック関数
(cvs-hook) を設定
psvar[2], psvar[3] が、もしもあれば、各々黄色と赤で右プロ
ンプトに表示
…
ということで、このフック関数でどのように psvar[2],
psvar[3] の値を設定するかがミソになる
22 / 25
右プロンプトにcvs状態表示・2
~/.zshrc(cvs 情報を右プロンプトに・2)
function +vi-cvs-hook() {
local cvsup=$(cvs -n update|egrep ’ˆ. ’|cut -c1|sort|uniq -c|
xargs|tr -d ’ ’|sed ’s/([0-9]+)([ˆ0-9])/21/g’)
[[ ! -n $cvsup ]] && return 0
local cvsinfo=$(echo ${cvsup}|sed ’s/C[0-9]+//’)
[[ -n $cvsinfo ]] && psvar[2]="$cvsinfo"
local cvswarn=$(echo ${cvsup}|sed ’s/.*(C[0-9]+).*/1/’)
[[ "$cvswarn" != "$cvsup" ]] && psvar[3]="$cvswarn"
}
cvs+set-messages に登録した関数名は “cvs-hook” だが、ここ
から呼び出される関数は “+vi-cvs-hook”
今は formats に文字列を1個しか登録していないが、formats
に文字列を複数登録しておけば、その個数だけ set-messages
の hook 関数群が呼び出される
その場合、対応するメッセージ($vcs info msg ? )の番号
(?の値)が、関数の第1引数($1)として渡される
23 / 25
右プロンプトにcvs状態表示・2(解説)
+vi-cvs-hook() 関数の1行目
cvs -n update で、変更を反映せずに cvs の状態をチェック
egrep ’ˆ. ’ で、マークの行だけを抜き出す
cut -c1 で、その1文字目だけを抜き出す
sort|uniq -c で、ソートして同じ文字数をカウント
xargs で、横一列に並べる
tr -d ’ ’ で、空白を削除
uniq -c では「文字の数」「文字」(例えば “12A”)という表示
なので、sed でそれを入れ替える(“A12” のように)
2行目:何も変更がなかったら終わり
3行目:cvsup から “C” の部分を切り取り、cvsinfo へ
4行目:cvsinfo があったら、psvar[2] に格納
5行目:cvsup から “C” の部分だけを抜き出し、cvswarn へ
6行目:cvsup に “C” がない場合は全く同じ文字列なので、
そうじゃない場合は cvswarn を psvar[3] に格納
24 / 25
右プロンプトにcvs状態表示
できた!
これにて、満足満足
25 / 25

More Related Content

Zshでデキるプロンプト