Chapter 3: 各種機能の使い方

3.1: var="foo bar"のとき、$varが期待の動作をしない

Bourne シェルから派生したものの大部分は、例えば


    var="foo bar"
  
のような複数語の変数は、コマンドを通るとき、または for foo in $var ループ中で使われるときに、単語に分割される。デフォルトでは、 zsh はそのような動作をしないので、変数はそのままである。(これはバグで はない。下記参照)。オプション SH_WORD_SPLIT は互換性を提 供する。

例えば、関数引数の数を表示するための関数 args を定義するには、


    args() { echo $#; }
  
であり、ここでの `var' の定義では、

    args $var
  
`1' を出力する。

    setopt shwordsplit
  
の後では、同じ関数は sh と ksh のように `2' を出力する。

意図的にスペースを含む変数に対して期待しない影響を及ぼすため、厳密な sh/ksh との互換性を必要としない限り、この動作が本当に必要であるかを 考慮しなさい。これは、他のシェルからスクリプトを呼び出した場合に厄介な クオーティング問題を引き起こす。zsh で単語分割の動作を処理する自然な方 法は、配列を介すことである。例えば、


    set -A array one two three twenty
  
(またはお好みで

    array=(one two three twenty)
  
でもよい)、下記のものは SH_WORD_SPLIT の設定に拘らず、

    args $array
  
`4' を出力する。配列は単一文字列よりも一層可変性がある。この手軽である が抑制しにくいメカニズムを常に利用すれば、おそらくスカラー文脈で自動的 な単語分割は行われないであろう。

内部のフィールドセパレータである $IFS の値にかかわらず、こ れは起こる。つまり、IFS=:; foo=a:b; args $foo では、1 とい う答えを得る。

`eval' の賢い使用法と、単語分割が起こる他の方法:


    sentence="Longtemps, je me suis couch\\'e de bonne heure."
    eval "words=($sentence)"
  
$sentence(この例での ' のようなシェルにとって特別な文字は、 常にクオートされていなければならないことに注意)の単語を配列として持つ $words に関して、または標準ではないがより確かなのは、一つの変数だけに対 して SH_WORD_SPLIT を有効にすることである。

    args ${=sentence}
  
は、上の args の定義では常に 8 を返す。(zsh の古いバージョ ンでは、${=foo}SH_WORD_SPLIT をトグルする が、現在では強制的に有効になる。)

zsh の関数とスクリプトでは、単語分割の "$@" の方法は常に利 用できる(だが厳密に言えば、これは単語分割ではなく配列分割を行なう)。 SH_WORD_SPLIT 設定に拘らず動作するので、これは $* よりも、より可搬性がある。その他の違いは、 $* は配列から空の引数を削除することである。この欠点の半分 は、展開が続く限り SH_WORD_SPLIT を無効にする ${==*} を使うことによって補うことが正できる。

zsh が `ksh' または `sh' という名前で呼び出されたとき、または(完全に同 義であるが)emulate ksh または emulate sh が 有効であるときに、SH_WORD_SPLIT が設定される。

3.2: どの初期化ファイルを置けば良いですか

zsh を起動するとき、様々な環境下で実行するための変更可能な4つのファイ ルがある。.zshenv.zprofile.zshrc.zlogin である。それらは通常ホームディ レクトリにあるが、それを変更するには変数 $ZDOTDIR を設定 する。ここでは、それらの使い方に関する幾つかの簡単なヒントを挙げる。こ れらは、システム管理者が全てのシェルに対して設定できるファイルでもある。 zsh を -f オプションを付けて起動することで、 /etc/zshenv を除く全てのファイルを実行しない。 このため、 管理者にとって /etc/zshenv はできるだけ簡潔にすることが重 要である。

4つのファイルが探査される順番(すべて存在する必要はない)は、 一通りだけである。しかし、.zprofile.zlogin は、シェルがログインシェルであるとき、つまり最初に ログインしたときか、またはもちろん -l オプション付きで実行 されたときにだけ実行される。全てのログインシェルは対話的である。順番は これらの間でだけ異なる。.zshrc の前または後で設定する必要 があるものがあるかどうかを判断すべきである。これらのファイルは環境変数 (つまり export コマンド)を設定するのに良い。なぜなら、 環境変数の再設定、また端末の適切な設定の検査なしで、これらの設定ファイ ルは全てのシェルに渡されるためである(ただ、xterm のような 端末エミュレートウィンドウに対する設定を変更したいなら、ここでは通常ロ グインシェルではないので、.zshrc 中に記述する必要がある)。

zsh で毎回起動される変更可能な唯一のファイル(-f オプショ ンを使わない限り)は、.zshenv である。だから、シェルが非対 話的であっても、ここにあなたがしたいことを記述すると良い。例えば、 EXTENDED_GLOB のような文法を変更するオプション、 limit による設定の変更、関数を見つける $fpath のようにあなたが確認したい変数が設定されているかな ど。あなたは .zshenv に出力を生成して欲しくないであろう。 .zshenv はスクリプトに影響を及ぼすので、これにオプションを 設定するのを好まない人もいる。だが、zsh スクリプトに可搬性を持たせるに は、やはり通常特別な操作を必要とする。

最後に、.zshrc は対話的なシェル毎に対して実行される。これ はログインシェルも含むが、その他シェルを実行したときもそうである。例え ば単に zsh とタイプしたときや、新しい端末エミュレートウィ ンドウを開いたときである。このファイルは、オプションを介しての編集動作 や bindkey の変更、ヒストリ保存の制御、またスクリプト中で 使用しないエイリアスの設定や、export されないが直接シェルを使っていると きにだけ使う他の雑多な設定をするためのものである。多分 .zshrc に出力を生成して欲しくなく、また、これが問題になり うることもある。例えば、他のホストから rsh を使うときなど である。ヒストリを保存するために、.zshrc に何を記述するか については質問 3.21 を見なさい。

3.3: `export' と ALL_EXPORT オプションの違い

通常は、export var を使って環境変数を設定する。 setopt allexport コマンドは、それ以降設定された変数(すで に設定されてものは含まない)を環境変数とする。

この手軽な記法は有用に思えるが、実際にはそうでない場面もある:

  1. シェルは、すべての変数を環境変数として保持するため、必要となるメモ リは二倍になる。このため、シェルは肥大化し、速度も遅くなる。
  2. for ループでのループ変数をも含む、すべての 変数が export される。これは大抵無駄である。
  3. ユーザが作った適当な変数が、あるコマンドにとって特別な意味を持つ可 能性がある。コマンドはすべてのシェル変数を参照できるので、これに対 する対応策はない。
これらの理由から、特定の使い方をしない限り、通常は ALL_EXPORT を使わないのが得策である。安全な使い方として、例 えば初期化ファイルで変数を設定する前にオプションを設定し、その後すぐに unset する。これらの変数だけが自動的に export される。

3.4: 特定のコマンドに対してスペル訂正/展開を止めるには

まず、多分初期化ファイルで setopt correctall を設定してい るので、zsh はコマンドラインの各単語のスペルをチェックする。しかし存在 するファイルを操作するコマンドに対しては、これは機能して欲しくないだろ う。

解決法は、気に入らないコマンドに対して、頭に nocorrect を 付けてエイリアスにすることである。例:


    alias mkdir='nocorrect mkdir'
  

展開を止めるにも、考え方は同じである:


    alias mkdir='noglob mkdir'
  
お望みであれば nocorrectnoglob の両方を設 定することもできるが、nocorrect が始めに来なくてはならない。 これはラインエディタが必要とするからであるが、一方 noglob はコマンドが調べられるときのみ使われる。

シェル関数は動かないことに注意しなさい。no... 命令は、残りのコマンドラ インがパースされる前に展開されるべきである。

3.5: xterm で meta key を有効にするには

マニュアルに書かれているように、zsh でメタキーを使うには、.zshrc やコマ ンドラインで bindkey -mebindkey -mv とす る。また、端末ドライバが `メタ' ビット文字を通すように設定する必要があ るだろう。stty pass8 というおまじないで通常は設定できる。 .zshrc のサンプル:


    [[ $TERM = "xterm" ]] && stty pass8 && bindkey -me
  
また、SYSVR4 風の pass8 のないシステムでは次のようになる。

    [[ $TERM = "xterm" ]] && stty -parenb -istrip cs8 && bindkey -me
  
(パリティ検知無効、最上位ビットを削らず、8 ビット文字を使う)。 これは、通常の emacs/vi キーマップを再定義する .zshrc で、bindkey の記 述のに来るように設定しなさい。また、 ~/.XdefaultseightBitOutput リソースを設定 する必要があるかもしれない。けれども、これはデフォルトで有効になってお り、普通は誰もこの設定をいじったりしない。

メタキーでのキーストロークを定義するのに bindkey は必要な いが、stty は必要である。

3.6: xterm のタイトルバーにディレクトリを自動表示させるには

ディレクトリを変更した際に、特別関数 chpwd を使えばよい。 次のサンプルは、標準出力が端末であるかをチェックし、端末が xterm やそれに準ずるもの、または sun-cmd であ る場合は、タイトルバーにディレクトリ名を置く。


  chpwd() {
    [[ -t 1 ]] || return
    case $TERM in
      sun-cmd) print -Pn "\e]l%~\e\\"
        ;;
      *xterm*|rxvt|(dt|k|E)term) print -Pn "\e]2;%~\a"
        ;;
    esac
  }
  

メッセージを違うものにしたいならば、%~ を変更しなさい。 (-P オプションは、記述をプロンプトのように解釈する。この場 合は、カレントディレクトリである。もちろん $PWD を使うこと もできるが、これは 見やすい ~ 表記を使わない。) xterm 起動時には、多分 chpwd を直接呼び出した いだろう。 これをするには、chpwd.zshrc で 定義または autoload された後に、chpwd を呼ぶだけである。

3.7: 補完リストに8ビットコードを使いたい

端末が 8 ビットコードを扱えるならば、バージョン 3.0.6 と 3.1 以降での最 も簡単な方法は、PRINT_EIGHT_BIT オプションを設定することで ある。原則として、コンピュータが `locale' システムを使い、ロカール変数 が適切に設定されていれば、zsh はこれを理解して、自動的に機能する。これ はとても複雑であるが、まだ設定されていないならば、オプションを設定して みなさい。zsh バージョン 3 ではより簡単であるので、ロカールを理解すれば よい。setlocale(3)zshparam(1) マニュアル ページを見なさい。最も簡単なのは、LC_ALL=en_US と設定する ことである。シェルの古いバージョンでは、簡単には設定できない。

3.8: なぜカーソル(矢印)キーが使えないか

端末によって、カーソルキーは異なったコードを送る。zsh の最近の主要なバー ジョでは、カーソルキーを使うことができる。もしこのような問題が起きたな ら、.zshrc に次のように記述しなさい。


    bindkey "$(echotc kl)" backward-char
    bindkey "$(echotc kr)" forward-char
    bindkey "$(echotc ku)" up-line-or-history
    bindkey "$(echotc kd)" down-line-or-history
  

vi モードでは、vi-backward-charvi-forward-char を使いなさい。

しかしバージョン 3.0 までは、任意の複数キーをバインドすることは問題が 起こりうるので、動作をチェックしてください。また 3.1.3 からは、デフォル トでより多くのシーケンスがサポートされている。つまり、 <ESC>[ で始まるものと同様に、 <ESC>O に続く ABCD という形式である。これは多いのかもしれな い。

ときどき起こる特有の問題は、矢印キーに対して異なるシーケンスを送る、ノー マルモードとキーパッドモードという二種類があるということである。これは 過去の遺物であるが、端末のモードが切り替わってしまうことがある。例えば、 悪いプログラムがモードを切り替えるシーケンスを送り、その後元に戻さない こともある。このことによって、うまく動作しなくなる。幸運にもこの場合、 矢印キーのシーケンスは標準であるようなので、単に両方とも設定をすればよ い。以下のコードで設定することができる。


    bindkey '\e[A'  up-line-or-history
    bindkey '\e[B'  down-line-or-history
    bindkey '\e[C'  forward-char
    bindkey '\e[D'  backward-char
    bindkey '\eOA'  up-line-or-history
    bindkey '\eOB'  down-line-or-history
    bindkey '\eOC'  forward-char
    bindkey '\eOD'  backward-char
  
大抵の曖昧な VT100 互換の端末でも、上の 8 つの設定は .zshrc に記述しても全く安全である。もちろん、第二引数に別 の関数を書くことも可能である。

3.9: 端末の動作がおかしくなります

端末として OpenWindows の cmdtool を使っているなら、エスケープシーケン ス(例えば カーソルキー)は吸い込まれるので、zsh には届かない。 shelltool を使うか、エスケープシーケンスを使うコマンドを避けなさい。 cmdtool のメニューからスクロールを無効にすることもできる(shelltool に 換えるよりも効果的である)。スクロールをさせたいなら、スクロールバーを有 効にした xterm を使ってみなさい。

もし stty を使って tty の設定を変更しており、問題でなければ、tty 設定が freeze しているかを確認しなさい。stty コマンドを使う前に、次のように タイプしなさい。


    ttyctl -u
  

一方、stty を使っていないならば、逆のことを必要とする問題があるかもし れない。ttyctl -f は端末を freeze させ、他のプログラムが 導くしゃっくり(kermit が知られている)から端末を保護する。

私自身が経験した問題(AIX 3.2 ワークステーション上の xterm)は、 `less' によって送られた termcap 非初期化シーケンスが automargins を off にする。実際にはシェルの問題ではないが、考慮する必要があるかもしれ ない。送られるシーケンスを止めるには、環境変数 LESS を `X' としなさい。他のプログラム(zsh ではないが)もそのシー ケンスを送るかもしれない。

これらが問題ではなく、(zsh の一部でない)外部コマンドのために 複雑になり、端末の設定が間違っている(例: 望んでいないのに、 ^V が `literal next character' として解釈される)と考え るならば、以下のものを試しなさい(この例の場合)。


    ttyctl -u
    STTY='lnext "^-"' commandname
  
または、すべてのコマンドから見えるように STTY を export しなさい。 zsh はそれ以降完全に端末をリセットしないことに注意しなさい。 そのコマンド自身が使うモードと、幾つかの特殊処理文字である (stty(1) のマニュアルを見なさい)。

3.10: Emacs シェルモードで zsh が使えなくなりましたが

(この情報は、Bart Schaefer と他の zsh-workers ML の方からです。)

Emacs 19.29 以降では、シェルバッファで "emacs" という端末タイプを使わ ず、"dumb" を使う。端末タイプが "emacs" の場合に、zsh は特殊な I'm-inside-emacs 初期化を呼び出すだけである。

多分、これを扱う最も信頼できる方法は、Emacs のシェルモードで t に設定されている環境変数 $EMACS を参照す ることである。.zshrc に以下のように記述すればよい。


    [[ $EMACS = t ]] && unsetopt zle
  

他の方法は、~/bin/eshell に


    #!/bin/sh
    TERM=emacs exec zsh
  
と記述し、chmod +x ~/bin/eshell とする。そして ~/.emacs に

   (setenv "ESHELL" "~/bin/eshell")
  
を加えることによって、emacs にシェルとして ~/bin/eshell を使うことを伝 える。

3.11: autoload されるはずの関数が(始めに)autoload されない

問題は、関数を autoload する方法が二通りあることである(詳しくは、マニュ アル zshmisc の AUTOLOADING FUNCTIONS を参照)。

  1. ファイルには関数の中身だけ書かれている。つまり、始めの function foo {foo () { という行がなく、 当然終りの foo () { もない。これは昔から zsh にある方 法である。利点はそのファイルがスクリプトのように実行されることであ り、スクリプトとしても使うことができる。xhead () { print -n "\033]2;$*\a"; } という関数を定義するには、print -n "\033]2;$*\a" とだけ書かれたファイルを作ればよい。
  2. ファイルには定義全体が書かれており、他のコードが含まれることもある。 これは関数がロードされる場合に実行されるので、関数自身が呼び出さ れる。これは ksh の方式である。同様な関数 xhead を定義 するには、通常の定義全体をファイルに書かなければならない。

3.0 以前の古い zsh では、前者の動作しかしないので、autoload のために関 数の中身だけを含むファイルにしなければならなかった。ファイルに標準的な 形式で関数を定義することもできたが、その関数が呼ばれるたびに再定義され た。

3.0.x では、autoload される関数をファイルに定義した場合、後者の方法が取 られる。あいにく、呼び出し時に再定義できる古い zsh での動作と互換性はな い。

3.1 では、オプション KSH_AUTOLOAD を使うことで ksh と完全 互換にすることができる。つまり、関数は必ず後者の形式でなければ ならない。このオプションが設定されていなければ、zsh は自動判別をする。 ファイルが後者の形式で、コメントや空白以外のものなしで関数全体が定義さ れている場合は、その定義されている関数を使用する。そうでなければ、前者 の動作を仮定する。emulate kshが設定されているなら、もちろ ん後者のように動作する。

(任意のディレクトリにある関数すべてを autoload するうまい方法は、 .zshrc に autoload ~/fns/*(:t) のように記述する。括弧中の フラグは、ファイル名のディレクトリ部分を削除し、関数名だけを残す。)

3.12: 数の表現方法

現在は ksh の文法も使える。例:


    let 'foo = 16#ff'
  
以下の2つも同じである。

    (( foo = 16#ff ))
  

    foo=$((16#ff))
  
文法の原形は次の通りである。

    (( foo = [16]ff ))
  
--- これは ksh のマニュアルの誤解が基となっていた。動作はするが、使用 は勧められない。ゆえに、

    echo $foo
  
は、`255' という答えを得る。明確に変数を整数型として宣言することがで きる。

    typeset -i foo
  
これは異なる影響を及ぼす。つまり、最初の代入で使われる基数(例では16進 数)は、`foo' が表示されるときに使われる(けれども、内部表現は変更され ない)。foo が常に10進数で表示されることを望むならば、次のように宣言し なさい。

    typeset -i 10 foo
  
これは出力の際に基数 10 を用いる。すでに存在する変数を、このようにし て出力の基数を変更することができる。$(( ... )) という方 法を使えば常に 10 進数で表示する。3.1.9 では、表示の際に基数を選択でき る新機能がある。

    print $(( [#16] 255 ))
  

3.13: プロンプト中で改行させたい

クオート中に、文字列の改行を入れることができる。例:


    PROMPT="Hi Joe,
    what now?%# "
  
もし、そのような動作を妨げる cshjunkiequotes オプションを設定するのが 嫌ならば、unsetopt cshjunkiequotessetopt cshjunkiequotes でこれを囲むか、またはオプション が設定される前に、.zshrc に記述する。

zsh の最近のバージョンは、`\n' のようなシーケンス表示を 解釈するクオート形式がある。しかしそうでなければ、シングルクオートのよ うに振舞う。これは文字列を $'...' で囲む。従って、


    PROMPT=$'Hi Joe,\nwhat now?%# '
  
は望み通りの結果を得る簡潔な方法である。プロンプト展開ではなく、クオー ティングであることに注意。これは `\n' を改行に変換するもの である。

3.14: bindkey ^a command-namestty intr ^- の動作がおかしい

おそらく、 extendedglob オプションが設定されているので、この場合 ^# がメタキャラクタになっている。 ^a という名前のファイル以外のすべてに マッチするので、その行はファイル一覧が続く bindkey として解釈される。 バックスラッシュで ^ をエスケープするか、 ^a をクオーテーションマークで囲みなさい。

3.15: \C-s\C-qにキーをバインドできない

フロー制御を stty -ixon で無効にしたり、stty startstty stop でキーを再定義したりしなけれ ば、デフォルトで control-s と control-q のキーはフロー制御を行う。 (これは zsh ではなくシステムが行う設定なので、zsh は単にそれを反映 しているだけである。)つまり、\C-s は端末への出力を全 て休止し、\C-q で再開する。

NO_FLOW_CONTROL というオプションがあり、 .zshrcsetopt noflowcontrol と書けば、 zsh はフロー制御を行わなくなり、hence それらのキーが使えるようにな る。

3.16: foo 関数の内部で foo コマンドを動かすには

ただ command foo とすればよい。これをエイリアスをする 必要はないが、関数で行わなければならない。次のようなメッセージが出 た場合は、 `foo' 関数内で `command' を使わずに `foo' を呼ぼうとして いる証である。


    zsh: job table full or recursion limit exceeded
  
foo が外部コマンドではなく、組み込みコマンドであるなら ば、代わりに builtin foo を使いなさい。

3.17: 単一の `!' のヒストリ置換の動作がおかしい

"echo !-2:$ !$" というコマンドの場合、1つめのヒストリ 置換は、後の単一の unqualified `!' 参照によるヒストリ置換のデフォル トとするため、!$ は !-2:$ と等しくなる。 CSH_JUNKIE_HISTORY オプションを設定すれば、単一の `!' は常に最後のコマンドを参照する。

3.18: ログアウトするとバックグラウンドジョブが死んでしまう

簡単な答え: kill しないように指定していないから。zsh には(csh/tcsh と異なり)、バックグラウンドジョブを kill するかどうかのオプションが ある。ログアウト時にバックグラウンドジョブを kill したくないのであれば、 `nohup' オプションを設定すれば良い。また、このオプションを指定してい る/いないに関わらず、頭に `nohup' を付けてコマンドを起動しても同様の 効果が得られる。(`nohup' は外部コマンドである)

内部コマンド `disown' は以下のような状況で大変便利である: ログアウト しようとした時に、zsh が "you have running jobs." と報告をするなら、 そこで、`disown' と入力することで、それらのプロセスを kill すること なくログアウトすることができる。(`disown' はそれらの子プロセスを「勘 当」するコマンドである)。同様に、シェルとの対話を行なわないコマンド (新しいウィンドウを作る X のアプリケーションなど)を起動した時に、シェ ルとの関係を切り離すのにも使える。また、バックグラウンドジョブの開始 に & を使わず、&! を使うようにする と、そのジョブは自動的に disown される。

3.19: ヒストリーを全部表示させるには

ヒストリーのエントリー 1 から表示させるには、history 1 とする。メモリ上にない始めのほうのエントリーは、暗黙的に省略される。

3.20: while {...} {...}などの選択的なループ構造が動く仕組み

zsh は sh の伝統的な形式である do を使うこともできる。


    while TEST; do COMMANDS; done
  
COMMANDS はいくつかのコマンドであり、{...} が使われること もある。規則はとても複雑であるが、sh 形式の規則が使えるため、大抵のスク リプトは安全に動き、互換性もある。もしわからなければ、以下の簡単なガイ ドを参考にしなさい。

動作をさせるためには、TEST の境界を明確にしなくてはならない。例えば、こ れは動作するが、


    while (( i++ < 10 )) { echo i is $i; }
  
これは動作しない。

    while let "i++ < 10"; { echo i is $i; }   # 間違い!
  
理由は while の後ろである。ここには複数のコマンドを記述す ることもでき、let "i++ < 10"; { echo i $i; } も有効であ る。つまり、パーサはどこまでが TEST なのか知らないのである。さらに、セ ミコロンを抜かすと、引数の {...} 部分 は let に引数になっ てしまうため、間違いである。改行はセミコロンと同様であるため、C 言語の ように次の行にブレースを置くことはできない。

よって、この文法を使う場合は、while に続く条件は囲まれなけ ればならない。((...))[[...]]{...}(...) がその効果を持つ。(これらはもち ろん、通常の意味も持ち、置き換えることはできない。)前例と同様に、ここ でもセミコロンを置くのは間違いとなる。


    while (( i++ < 10 )); { echo i is $i; }   # 間違い!
  

ifuntil 文での true も同様である。


    if { true } { echo yes } else { echo no }
  
しかし、単語リストが必要である for では、パーサは最初のセ ミコロンまでを必要とすることを知っているので、セミコロンを使うことがで きる。

    for foo in a b; { echo foo is $a; bar=$foo; }
  
同様の理由で、repeatcaseselect 文でも使うことができる。実際には、 repeat は繰り返し回数は一単語であることをパーサは知ってい るので、セミコロンさえも必要ない。

SHORTLOOPS オプションの動作には依存しない(マニュアルを参照)。これは、 混乱の元となるため、プログラム中での使用は勧められない。

3.21: なぜヒストリーが保存されないか

zsh では、終了時にヒストリを保存するには、3つの変数を設定する必要が ある。例:


    HISTSIZE=200
    HISTFILE=~/.zsh_history
    SAVEHIST=200
  
$HISTSIZE は内部に保持する数、 $HISTFILE はヒストリを保存するファイル名、 そして忘れやすいのが、どのくらい保存するかを設定する $SAVEHIST である。簡潔な設定としては、上のように $HISTSIZE と同じ値を設定する。他にもヒストリに関する様々 なオプションがあるので、マニュアルを参照しなさい。

3.22: 変数の値を他の変数として評価させるには

仮に、EDITOR という文字列が代入された変数 $E があり、変数 $EDITOR には emacs という文字列が代入されているとする。1ステップで $E から emacs という文字列を得るには、どのようにすればよい のか?

1ステップでこれを行なう標準的な方法はない。しかし、これを行なうための zsh の熟語(バージョン 3.0 以降で使える)がある。


    print ${(e)E:+\$$E}
  
今は (e) は無視するとして、:+ の意味は、もし $E が設定されていたら、その後のもの、つまり \$$E と置き換えるということである。通常規則では、これは $EDITOR に展開される。最後の (e) は、`最終的 に展開されたものを評価する' という意味である。

標準のシェルでの方法は、eval を使うことによって同様の結果 が得られる。


    eval echo \$$E
  

バージョン 3.1.6 では、新たなフラグで直接行うことができる。 ${(P)E}.

ささいなことではあるが、${${E}} という文法は有効であり、同 様の効果を期待すると主張する人が時々いる。確かにそうなのかもしれないが、 初期の zsh では、同様のパラメータに対して異なる置換が行われた。例えば、 ${${file##**/}%.*}$file の最後のスラッシュ までを削除し、その後最後のドット以降を削除する。よって ${${E}} では、内側の ${...} は何も行なわない。

3.23: 改行のない出力をプロンプトで上書きしてしまうのを防ぐには

以下の例で問題なのは、


    % echo -n foo
    % 
  
foo は、プロンプト % で上書きされることで ある。簡単な答え: .zshrcunsetopt promptcr と書く。プロンプトの前に改行(CR, キャリッジリター ン)を表示するオプション PROMPT_CR は、デフォルトで設 定されている。これは、行が左端の列から始まらない限り、右端のプロン プト($RPROMPT, $RPS1)が適切な位置に表示 されず、複数行編集の場合は行位置に混乱をきたす。 PROMPT_CR なしでも、プロンプトに改行を入れることで、強制的 に同様のことを起こすこともできる(これについては 質問 3.13 を見なさい)。

3.24: xterm でのカットアンドペーストがうまくいかない

主要な UNIX システムでは、あるウインドウからテキストをカットして、他の ウインドウにペーストすることは容易に可能であろう。しかし稀に、端末の扱 いによって問題が起こりうる。大抵のプログラムは端末が `canonical input mode' であることを仮定している。これは、プログラムが入力行全体を一度に 受け取ることを意味する。しかし、行を編集するには、シェルは一文字ずつ受 け取らなければならず、`non-canonical input mode' でなければならない。問 題のシステムでは、モードを切り替えたときに、入力が消失したり再整列され ることがある。実際には以下のようなわずかな違いである。

  1. プログラムが走っているときにペーストした場合、シェルは後でまとめて 処理をする。伝統的に、問題があることが知られているシステムでのみテ ストが行われ、他のシステムでは行われない(例えば IRIX のとあるバー ジョン)。また、継続した行は適切に処理されなかった。バージョン 3.0.6 と 3.1.6 では、より信頼できる処理が行われる。
  2. シェルが入力待ちのとき、ひとつ以上のまとまったコマンドをペーストし たとする。あいにく、これは難しい問題である。最初のコマンドが実行さ れたときに、ラインエディタがすでに機能しているならば無効にしなけれ ばならない。しかしシェルは、残りのテキストがコマンドなのかシェルへ の命令なのかを知らないので、容易に行うことはできない。だが、問題が あるならば、騙すこともできる。`{'と単独で入力してから ペーストし、その後 `}' を入力しなさい。そうすれば、シェ ルは最後の閉括弧を読み込むまで何も実行しない。入力全ては継続した行 として読み込まれる(信頼性のため、上で述べたような修正が必要である)。

3.25: カラー xterm で カラープロンプトを表示するには

マニュアルから色を着けるためのシーケンスを見つけなければならない。私が 知る限りのカラー対応の端末エミュレータでは、ANSI 標準である。最近の zsh(3.1.6 以降)では、これを取り扱うテーマシステムが用意されている。こ れについて知らなくても、インストールされた関数 `colors' (白黒画面で読んでいないならば、`colours' という意味である)がエスケープ シーケンスを渡してくれる。多分次のようなコードになるだろう(Oliver Kiddle から)。


    PS1=$'%{\e[1;31m%}<ここに残りのプロンプトを書く>%{\e[0m%}'
  
$' というクオート形式は、`\e' という文字をエ スケープ文字に置換する。これは 3.1.4 以降で動作するため、3.0.x を使って いるならば以下のようしなければならない。

    PS1="$(print '%{\e[1;31m%}<ここに残りのプロンプトを書く>%{\e[0m%}')"
  
`%{...%}' は、プロンプト中で文字として表示されない文字列を 囲むのに使われるため、行編集に悪影響を与えるプロンプト長の計算ミスをし ない。`<ESC>[1;31m というのはプロンプトを赤色にし、 `<ESC>[0m' は通常の表示に戻すので、行の残りは変化し ない。