【コラム】

漢のzsh

2 取りあえず、プロンプトを整えておく。カッコつけたいからね

    後藤大地  [2007/02/15]

    補完の深みに入るまえに、今回は基本の設定をしてしまおう。設定は~/.zshrcファイルに書き込んで、source ~/.zshrcで反映だ。zshに直接入力して設定を有効にさせてみてもいいが、~/.zshrcに書き込まないと、次に起動したときzshはきれいさっぱり忘れているので気をつけるように。

    環境変数LANG

    まずは、環境変数LANGを設定しよう。zshから実行するコマンドやアプリケーションがLANGで指定したロケールで動作するようになる。最近のOSなら設定はリスト1.1のようにUTF-8を設定すればいい。Linux/FreeBSDで古いディスとリビーションやバージョンを使っている場合、もしくは、LaTeXなどUTF-8へ対応していないアプリケーションを使う場合はリスト1.2のようにEUC-JPを設定しておけばいいだろう。

    リスト1.1 環境変数LANGをja_JP.UTF-8へ設定 - Linux/FreeBSD/Mac OS X

    export LANG=ja_JP.UTF-8

    リスト1.2 環境変数LANGをja_JP.eucJPへ設定 - Linux/FreeBSD - LaTeXなどEUC-JPを要求するアプリを使う場合など

    export LANG=ja_JP.eucJP

    なんでログインシェルでLANGを設定するかだが、これには理由がある。シェルから起動されるコマンドやアプリケーションにはシェルで設定された環境変数が引き継がれる。だからログインシェルの設定ファイルでLANGを設定するわけだ。

    プロンプト

    プロンプトは、まさにシェルの「顔」。最も好みがでる設定のひとつだ。漢としては、カッコつけるためにもこだわりたい。

    zshには、プロンプトでカッコつけるための強力な設定がある。せっかくなので設定して御利益をうけておこう。というか、プロンプトを同じにしておくと、シェルを変えてもだれも気付いてくれないし……

    設定には、シェル変数PROMPT/PROMPT2/PROMPT3/PROMPT4/SPROMPTが利用できる(ほかのシェルと同じ名前のprompt、PS1、PS2、PS3、PS4も用意されているが、動作は一緒だ)。

    変数の意味についてはここここあたりをご覧いただくとして、少なくともPROMPT、PROMPT2、SPROMPTあたりを設定しておけばいいだろう。リスト2.1あたりが基本的といったところだ。

    リスト2.1 プロンプトの設定例 - PROMPT、PROMPT2、SPROMPTあたりは設定しておこう

    PROMPT="%/%% "
    PROMPT2="%_%% "
    SPROMPT="%r is correct? [n,y,a,e]: "

    PROMPTは通常のプロンプト、PROMPT2はforやwhile/複数行入力時などに表示されるプロンプト、SPROMPTは入力ミスを確認する場合に表示されるプロンプトだ。

    図2.2 プロンプトにカレントディレクトリを表示させている

    図2.3 複数行の入力や制御構文入力の場合に構文名がプロンプトに表示されている

    図2.4 コマンド入力ミスを確認する場合のプロンプト

    PROMPT、PROMPT2、SPROMPTで使われている「%/」や「%_」、「%%」がそれぞれ意味のある値になっている。ここあたりにそれぞれ説明があるので参考にしてほしい。結構変態的なプロンプトも設定できるので、プロンプトを設定しながら悶絶してみるのもいいだろう。

    ちなみに筆者が使っているプロンプト設定はリスト2.5。一般ユーザとrootで表示されるプロンプトの色合いが変わる。

    あと、ローカルでの作業とsshでリモートログインして作業する場合も色合いが変わる。うっかりリモートをローカルと勘違いして設定変更とかファイルを削除とか、お取引先を困らせたりしがち、というかしたことがあるので、それを防止するためだ。自分のマシンだと思って隣りの人のマシンの設定を書換えながら、お互い頭を抱えたこともある。まさに時間の無駄である。

    ちなみに、ホストごとに出る色を変えるようにするかと考えたこともあるが、見にくいホストとかが出てきがちだし、そもそもホストと色の対応も覚えられない。実際問題使い物にならないね、ということで、これはやめた。

    リスト2.5 プロンプトの設定例 - 応用例 - 状況によってプロンプトを変えている。色もつく

    case ${UID} in
    0)
        PROMPT="%B%{^[[31m%}%/#%{^[[m%}%b "
        PROMPT2="%B%{^[[31m%}%_#%{^[[m%}%b "
        SPROMPT="%B%{^[[31m%}%r is correct? [n,y,a,e]:%{^[[m%}%b "
        [ -n "${REMOTEHOST}${SSH_CONNECTION}" ] && 
            PROMPT="%{^[[37m%}${HOST%%.*} ${PROMPT}"
        ;;
    *)
        PROMPT="%{^[[31m%}%/%%%{^[[m%} "
        PROMPT2="%{^[[31m%}%_%%%{^[[m%} "
        SPROMPT="%{^[[31m%}%r is correct? [n,y,a,e]:%{^[[m%} "
        [ -n "${REMOTEHOST}${SSH_CONNECTION}" ] && 
            PROMPT="%{^[[37m%}${HOST%%.*} ${PROMPT}"
        ;;
    esac

    図2.6 プロンプトには色がつき、一般ユーザとrootで色合いが変わるよになっている。背景が白でも黒でも使えるような色合いにしてある

    図2.7 sshでリモートログインしている場合にはプロンプトにホスト名も表示するようにしてある。相手のマシンでおかしな作業をするのを防止するためだ

    色の指定は%{^[[31m%}の31の部分だ。ここの数字を変えるを表示される色もかわる。色が表示されるかどうか、どんな色が表示されるかはターミナルによって変わってくるので、このあたりを参考にして数字をかえてみてほしい。これはtcshのマニュアルだが、最後の方にLS_COLORSの説明があって、そこで数値と色の関係が説明されている。

    ところで、上記設定をコピーして使ってみても、思ったようにはならないはず。「^[[31m/home/daichi%^[[m 」といったプロンプトになってしまうはずだ。これは"^["が実際には「エスケープ」といわれるものだからだ。

    なので上記設定を~/.zshrcに書き込んだら、"^["の部分を削除してエスケープに置き換えればいい。viで編集するならCtrl-v ESCで入力できるし、EmacsならCtrl-q ESCで入力できる。エスケープを直接設定ファイルに記述することを嫌って、echoやprintfコマンドを使う場合もある。好きな方を選べばいい。ただ、コマンドだとプラットフォームごとに動いたり動かなかったりするので、ここでは直接書いて使っている。

    パスの表示が左にあって移動するごとに長さがかわるのが気になる場合は、図2.8のように右に表示させることもできる。右に表示したいものについてはRPROMPT、RPROMPT2を設定すればいい。

    右プロンプトの利点としては、入力がぶつかると消えるというのがある。zshのパワーをもってすればパスの省略表示といったことも簡単にできるのだが、筆者としてはこちらの方が好みかも。

    図2.8 右にパスを表示させた場合 – 左プロンプトの長さがかわらないので便利

    プロンプトと入力がぶつかると消える。便利だ。

    この画像は、担当編集O氏のシェルで、設定は

    PROMPT="%m:%n%% "
    RPROMPT="[%~]"
    SPROMPT="correct: %R -> %r ? "

    となっている。なんのこだわりも見られないのはいかがなものか。

    ターミナルのタイトル

    ターミナルのタイトルも、プロンプトと同様こだわりたいところだ。タイトルを変更できるターミナルとそうでないものとあるのだが、仕組みとしてはリスト3.1のように書いておけばいい。この場合、ターミナルのタイトルに「ユーザ@ホスト:カレントディレクトリ」が表示されるようになる。

    リスト3.1 ターミナルのタイトルに「ユーザ@ホスト:カレントディレクトリ」を表示させる設定

    case "${TERM}" in
    kterm*|xterm)
        precmd() {
            echo -ne "\033]0;${USER}@${HOST%%.*}:${PWD}\007"
        }
        ;;
    esac

    仕組みとしてはprecmd()組み込み関数を使って、こいつにターミナルへシーケンス文字を送信するコマンドを書いているというわけだ。

    分岐構文を使ってkterm*とxtermに対象を絞っているのは、コンソールのようにタイトルバーの存在しないプラットフォームで処理をしないようにするためだ。愛用しているターミナルで動作しない場合、kterm*|xterm)のあたりを変更すればいいだろう。

    今回はここまで。

    最後に…… こういってはなんだが、実際問題シンプルな方が使いやすいですよ?

    おまけ

    今回説明した設定内容を設定ファイルにまとめたものを掲載しておく。ついでにbashとtcshで同じような設定をする場合の例も紹介しておく。zshが使えない環境での参考にしてみてほしい。

    リスト4.1 今回の設定ファイルまとめ ~/.zshrc

    ## Environment variable configuration
    #
    # LANG
    #
    export LANG=ja_JP.UTF-8

    ## Default shell configuration
    #
    # set prompt
    #
    case ${UID} in
    0)
        PROMPT="%B%{^[[31m%}%/#%{^[[m%}%b "
        PROMPT2="%B%{^[[31m%}%_#%{^[[m%}%b "
        SPROMPT="%B%{^[[31m%}%r is correct? [n,y,a,e]:%{^[[m%}%b "
        [ -n "${REMOTEHOST}${SSH_CONNECTION}" ] && 
            PROMPT="%{^[[37m%}${HOST%%.*} ${PROMPT}"
        ;;
    *)
        PROMPT="%{^[[31m%}%/%%%{^[[m%} "
        PROMPT2="%{^[[31m%}%_%%%{^[[m%} "
        SPROMPT="%{^[[31m%}%r is correct? [n,y,a,e]:%{^[[m%} "
        [ -n "${REMOTEHOST}${SSH_CONNECTION}" ] && 
            PROMPT="%{^[[37m%}${HOST%%.*} ${PROMPT}"
        ;;
    esac

    # set terminal title including current directory
    #
    case "${TERM}" in
    kterm*|xterm)
        precmd() {
            echo -ne "\033]0;${USER}@${HOST%%.*}:${PWD}\007"
        }
        ;;
    esac

    リスト4.2 bashで同じような設定をした場合 ~/.bashrc

    ## Environment variable configuration
    #
    # LANG
    #
    export LANG=ja_JP.UTF-8

    ## Default shell configuration
    #
    # set prompt
    #
    case ${UID} in
    0)
        PS1='\[\033[1;31m\]${PWD}\$\[\033[0m\] '
        PS2='\[\033[1;31m\]>\[\033[0m\] '
        [ -n "${REMOTEHOST}${SSH_CONNECTION}" ] && PS1='\[\033[1;30m\]\h'" ${PS1}"
        ;;
    *)
        PS1='\[\033[31m\]${PWD}\$\[\033[0m\] '
        PS2='\[\033[31m\]>\[\033[0m\] '
        [ -n "${REMOTEHOST}${SSH_CONNECTION}" ] && PS1='\[\033[37m\]\h'" ${PS1}"
        ;;
    esac

    # set terminal title including current directory
    #
    case "${TERM}" in
    kterm*|xterm)
        PROMPT_COMMAND='echo -e "\033]0;'"${USER}@${HOSTNAME%%.*}:"'${PWD}\007\c"'
        ;;
    esac

    リスト4.3 tcshで同じような設定をした場合 ~/.tcshrc

    ## Environment variable configuration
    #
    # LANG
    #
    setenv LANG ja_JP.UTF-8

    ## Default shell configuration
    #
    # set prompt
    #
    if ( 0 == ${uid} ) then
        set prompt="%B%{\033[31m%}%/%#%{\033[m%}%b "
        set prompt2="%B%{\033[31m%}%R%#%{\033[m%}%b "
        set prompt3="%B%{\033[31m%}%R is correct? [y,n]:%{\033[m%}%b "
        if (${?REMOTEHOST} || ${?SSH_CONNECTION}) then
            set prompt="%{\033[37m%}${HOST:ar:au} ${prompt}"
        endif
    else
        set prompt="%{\033[31m%}%/%%%{\033[m%} "
        set prompt2="%{\033[31m%}%R%%%{\033[m%} "
        set prompt3="%{\033[31m%}%R is correct? [y,n]:%{\033[m%} "
        if (${?REMOTEHOST} || ${?SSH_CONNECTION}) then
            set prompt="%{\033[37m%}${HOST:ar:au} ${prompt}"
        endif
    endif

    ## terminal configuration
    #
    if ( ${?TERM} ) then
        switch ( "${TERM}" )
        case kterm:
        case kterm-color:
        case xterm:
            # set terminal title
            alias postcmd echo -n '"^[]2;${TERM:s/-/./:r} ${HOST:ar}:${cwd}^G"'

            breaksw
        endsw
    endif

    新着記事

    特設サイトの情報

      人気記事

      一覧

        イチオシ記事

        新着記事

        特別企画

        マイナビニュースマガジン