Yash マニュアル: 対話モード
Author: magicant
Description: Yash の対話モードでの動作について

# 対話モード

対話モードは、利用者が直接シェルを操作することを意図したモードです。シェルの起動時に `-i` オプションを指定した場合 (その他対話モードが有効になる条件が満たされている場合)、シェルは対話モードになります。シェルが起動した後は、そのシェルの対話モードのオン・オフを切り替えることはできません。

対話モードが有効な時……

- シェルの起動時に初期化スクリプトを読み込んで実行します。
- コマンドを読み込む際にメールチェックを行い、プロンプトを表示します。ジョブ制御が有効ならジョブの状態変化も表示します。端末の種類によっては行編集が使えます。
- 実行したコマンドは自動的にコマンド履歴に登録されます。
- 実行したコマンドが SIGINT/SIGPIPE 以外のシグナルによって中断されたとき、シェルはそのことを示す警告メッセージを標準エラーに出力します。
- ファイルのリダイレクトの対象ファイルを指示するトークンに対してパス名展開を行います。
- 非同期コマンドの標準入力が自動的に /dev/null にリダイレクトされません。(POSIX 準拠モードのみ)
- コマンド解釈・実行時に文法エラーや展開エラーが発生してもシェルは終了しません。(シェルの終了)
- SIGINT, SIGTERM, SIGQUIT シグナルを受けても、シェルは終了しません。
- シグナル受信時の挙動がシェルの起動時に最初から無視に設定されていても trap 組込みコマンドでシグナル受信時の挙動を変更できます。
- 特殊パラメータ `-` の値に `i` が含まれます。
- シェル実行中に `LC_CTYPE` 変数の値が変わった時、それを直ちにシェルのロケール情報に反映します。(POSIX 準拠モードを除く)
- Exec オプションが無効な時でもコマンドを実行します。
- Ignoreeof が効果を発揮します。
- Exit 組込みコマンドでシェルを終了しようとした時、停止しているジョブがあれば、シェルは警告を表示してすぐには終了しません。このときは続けざまにもう一度 exit コマンドを実行すると本当にシェルを終了させることができます。シェルへの入力が終わりに達した場合も同様です。
- Suspend 組込みコマンドでシェルを停止させようとした時、シェルがセッションリーダーならエラーを出力して停止しません。
- ドット組込みコマンドで読み込むスクリプトファイルが見つからなくても、シェルは終了しません。
- Exec 組込みコマンドでコマンドの実行に失敗したときでもシェルは終了しません。(POSIX 準拠モードのときを除く)
- Wait 組込みコマンドで待っているジョブが終了したとき、そのことを示すメッセージを出力します。(ジョブ制御が有効な時のみ。POSIX 準拠モードを除く)
- Read 組込みコマンドが二行目以降を読むときプロンプトを出します。

## プロンプト

対話モードでは、シェルはコマンドの入力を読み取る直前にプロンプトを標準エラーに出力します。プロンプトの内容は `PS1` 変数で指定します。ただし、複数行にわたるコマンドを読み取る際、二行目以降の読み取りには `PS1` ではなく `PS2` 変数の値がプロンプトとして表示されます。

プロンプトの表示の際には、まず `PS1` (または `PS2`) 変数の値がパラメータ展開・コマンド置換・数式展開で展開されます (ただし POSIX によればパラメータ展開だけが行われることになっています)。この展開後の値は以下の通り解釈され、その結果がプロンプトとして標準エラーに出力されます。

POSIX 準拠モードでは、値に含まれる `!` はこれから入力しようとしているコマンドの履歴番号に変換されます。感嘆符そのものをプロンプトに表示させるには `!!` と二つ続けて書きます。これ以外の文字はプロンプトにそのまま表示されます。

POSIX 準拠モードでないときは、バックスラッシュで始まる以下の記法が解釈されます。これらの記法以外の文字はそのままプロンプトに表示されます。

`\a`
  ベル文字 (ASCII コード番号 7)
`\e`
  エスケープ文字 (ASCII コード番号 27)
`\j`
  現在シェルが抱えているジョブの数
`\n`
  改行文字 (ASCII コード番号 10)
`\r`
  復帰文字 (ASCII コード番号 13)
`\!`
  これから入力しようとしているコマンドの履歴番号
`\$`
  シェルの実効ユーザ ID が 0 のとき `#`
  シェルの実効ユーザ ID が 0 以外のとき `$`
`\\`
  バックスラッシュ `\`
`\[`
`\]`
  この二つの記法は、実際には端末に表示されないプロンプトの一部分を指示するのに使います。`\[` と `\]` で囲んだ部分は、行編集がプロンプトの文字数を計算する際に、文字数に数えられません。端末に表示されないエスケープシーケンスなどをプロンプトに含める際は、その部分を `\[` と `\]` で囲んでください。この指定を怠ると、行編集の表示が乱れることがあります。
`\fフォント指定.`
  行編集を使用している場合、この記法は端末のフォントの表示を変更するための特殊な文字の羅列に変換されます (端末が対応している場合のみ)。行編集を使用していない場合や端末が対応していない場合は、この記法は単に無視されます。フォント指定の部分にはフォントの種類を指定するための以下の文字を指定します。
  `k`
    文字の色を黒にする
  `r`
    文字の色を赤にする
  `g`
    文字の色を緑にする
  `y`
    文字の色を黄にする
  `b`
    文字の色を青にする
  `m`
    文字の色をマゼンタにする
  `c`
    文字の色をシアンにする
  `w`
    文字の色を白にする
  `K`
    背景の色を黒にする
  `R`
    背景の色を赤にする
  `G`
    背景の色を緑にする
  `Y`
    背景の色を黄にする
  `B`
    背景の色を青にする
  `M`
    背景の色をマゼンタにする
  `C`
    背景の色をシアンにする
  `W`
    背景の色を白にする
  `t`
    文字または背景の色を明るくする (上記の文字・背景の色を変更する文字の直後でのみ有効)
  `d`
    文字と背景の色を標準状態に戻す
  `s`
    文字を目立たせる
  `u`
    文字に下線を引く
  `v`
    文字の色を反転させる
  `b`
    文字を点滅させる
  `i`
    文字の色を暗くする
  `o`
    文字を太く目立たせる
  `x`
    文字を見えなくする
  `D`
    色と装飾を標準状態に戻す
  文字と背景の色は最終的に端末によって決まるため、実際にはここで指定した色と異なる色で表示されることがあります。

入力するコマンドの右側に表示されるプロンプトを指定することもできます (右プロンプト)。`PS1`/`PS2` 変数に対応する右プロンプトは `PS1R`/`PS2R` 変数で指定します。

また、プロンプトのフォントだけでなく、入力するコマンドのフォントを変えることもできます。`PS1S` (または `PS2S`) 変数に上述のフォントを指定するシーケンスを指定することで、コマンド入力時のコマンドのフォントが変わります。

POSIX 準拠モードでないときは、プロンプトを出す前に `PROMPT_COMMAND` 変数の値がコマンドとして実行されます。

## コマンド履歴

コマンド履歴は実行したコマンドを記録し後で再び実行することのできる機能です。対話モードでシェルが読み込んだコマンドは自動的にコマンド履歴に記録されます。履歴に記録したコマンドは行編集で呼び出して再実行することができます。また fc・history 組込みコマンドで履歴のコマンドを再実行したり編集したりすることもできます。

コマンドは行単位で履歴に記録されます。空白以外の文字を一切含まない行は履歴には記録されません。また histspace オプションが有効なときは空白で始まる行は履歴に記録されません。

コマンド履歴の内容は `HISTFILE` 変数で指定されるファイルに保存されます。対話モードのシェルの起動後に履歴関連の機能が初めて使用されるとき、`HISTFILE` 変数の値をファイル名とみなしてファイルを開きます。既にファイルに履歴データが保存されている場合は、それが読み込まれます。ファイルが存在しないか内容が履歴データではない場合は、新しい履歴ファイルに初期化されます。`HISTFILE` 変数が存在しない場合やファイルを開くことができない場合は履歴はファイルに保存されませんが、履歴機能自体は使用できます。

シェルが記録するコマンドの数は `HISTSIZE` 変数で指定します。履歴の件数がこの変数の値を超えると順次古いデータから削除されます。この変数が存在しない場合または値が自然数でない場合は、履歴は 500 件まで記録されます。

`HISTFILE` および `HISTSIZE` 変数は履歴機能が初めて使用されるときにのみ参照され、それ以降は変数を再設定しても履歴機能の動作に影響しません。履歴機能が利用されるときというのは、具体的には以下のタイミングです。

- Fc または history 組込みコマンドを実行したとき
- 行編集を使用してコマンドを入力するとき (履歴データを行編集の中で使わなくても履歴機能は使われます)
- 入力したコマンドが履歴に登録されるとき

このため `HISTFILE`・`HISTSIZE` 変数は原則としてシェルの起動時に読み込まれる初期化スクリプトの中で設定する必要があります。

複数のシェルプロセスが同じ履歴ファイルを使用している場合、これらのシェルは一つの履歴データを共有します。このとき例えばあるシェルプロセスで実行したコマンドを別のシェルプロセスで実行することができます。同じ履歴を使用しているシェルの間で `HISTSIZE` が異なっていると履歴が正しく共有されないので、`HISTSIZE` の値は統一するようにしてください。

Yash は独自の形式の履歴ファイルを使用しているため、履歴ファイルを他の種類のシェルと共用することはできません。

履歴に同じコマンドを記録する無駄を解消するため、`HISTRMDUP` 変数を使用することができます。新しくコマンドを履歴に記録しようとする際、すでに同じコマンドが最近の $HISTRMDUP 件の履歴データの中に記録されていれば、その既に記録されているコマンドは履歴から削除されます。

## メールチェック

対話モードのシェルには、電子メールが届いたらそれを知らせる機能があります。これは所定のファイルの更新日時を調べて、更新日時が変わっていたらメッセージを表示するというものです。受信したメールのデータが保存されるファイルをチェック対象として指定しておくことで、メールを受信したときにメッセージが表示されるようになります。

ファイル更新のチェックはシェルがプロンプトを出す直前に行います。チェックを行う間隔を `MAILCHECK` 変数で指定することができます。この変数で指定した秒数が経過するごとに、シェルはプロンプトを出す直前にチェックを行います。この変数の値が 0 になっている場合は、プロンプトを出す直前に毎回チェックを行います。また変数の値が 0 以上の整数でない場合は、チェックは一切行いません。

更新日時をチェックする対象のファイルは `MAIL` 変数で指定します。この変数にチェックしたいファイルのパス名を指定しておくと、シェルはそのファイルの更新日時をチェックします。ファイルの更新日時が前回チェックしたときと変わっていたら、新着メールを知らせるメッセージを標準エラーに出力します。(ただしファイルが空のときはメッセージは出ません (POSIX 準拠モードのときを除く))

複数のファイルをチェックの対象にしたい場合やメッセージを自分で指定したい場合は、`MAIL` 変数の代わりに `MAILPATH` 変数を使うことができます。`MAILPATH` 変数が設定されている場合は、`MAIL` 変数の設定は無視されます。`MAILPATH` 変数の値には、複数のファイルのパス名をコロン (`:`) で区切って指定することができます。シェルは毎回のチェックでそれぞれのファイルの更新日時を調べ、ファイルが更新されていたらメッセージを表示します。メッセージを自分で指定するには、パス名の直後にパーセント (`%`) を置き、続けて表示させたいメッセージを置きます。それぞれのファイルごとに異なるメッセージを指定することができます。(パーセントをパス名とメッセージとの区切りではなくパス名の一部としたい場合はパーセントをバックスラッシュでクォートしてください) パーセントの後に指定されたメッセージは、表示の前にパラメータ展開されます。例えば `MAILPATH` 変数の値が `/foo/mail%New mail!:/bar/mailbox%You've got mail:/baz/mail\%data` だとすると、ファイル /foo/mail が更新されたときは New mail! が、/bar/mailbox が更新されたときは You've got mail が、/baz/mail%data が更新されたときはデフォルトのメッセージが表示されます。