対話モードか否か?
10月末に行われた第19回シェル芸勉強会の問題をふと思い出すことがありました。
最初の問題が、端末で実行した場合とシェルスクリプトに書いて実行した場合で動きを変える、という内容でした。出題者上田さんの解答例では、aliasが効くかどうかで判定していました。
問題と解答は、出題者上田さんが公開されているページQ1をご覧ください。
この問題の意味は、シェルの状態が対話(インタラクティブ)モードかどうか?の判定をどうするかということだと思います。
ところでFreeBSDのデフォルトログインシェルはtcshです。FreeBSDのサーバで作業をしていた時に、ふとシェルの設定ファイルを確認してみました。デフォルトで提供される設定ファイルが下記のようになっています。
> tail -n +24 .cshrc if ($?prompt) then【←シェル変数promptが定義されているか?】 # An interactive shell -- set some stuff up #set prompt = "%N@%m:%~ %# " #set promptchars = "%#" set prompt = '\n%n@%M:%~\n%# ' set filec set history = 1000 set savehist = (1000 merge) set autolist = ambiguous # Use history to aid expansion set autoexpand set autorehash set mail = (/var/mail/$USER) if ( $?tcsh ) then bindkey "^W" backward-delete-word bindkey -k up history-search-backward bindkey -k down history-search-forward endif endif
プロンプトが設定されたシェル変数prompt
が定義されているか?を判定するif文があります。
ここでシェルの状態が対話(インタラクティブ)モードなのか?どうか判定しているようです。
実際に確認してみました。シェルはtcshです。
スクリプト(非対話モード)は、シェルの-c
オプションを使ってコマンド文字列を指定する方法を使いました。
## 対話モード > echo $prompt \n%n@%M:%~\n%# ## 非対話モード > tcsh -c 'echo $prompt' prompt: Undefined variable.
sh、bash、zshのプロンプトはPS1
というシェル変数で設定します。
tcshと同様に、対話モードか非対話モードで変化するか、bashを使って実際に確認してみました。
## 対話モード $ echo $PS1 \n\u@\h:\w\n\$ ## 非対話モード $ bash -c 'echo $PS1' 【出力無し】
非対話モードでは出力がありませんが、PS1が未定義なのかどうかが確認出来ません。
そこで未定義の変数を参照したらエラーが発生するset -u
を使って確認しました。
## 対話モード $ set -u; echo $PS1; set +u \n\u@\h:\w\n\$ ## 非対話モード $ bash -c 'set -u; echo $PS1' bash: PS1: 未割り当ての変数です
つまり、非対話モードの場合はシェル変数PS1が未定義のようです。
シェル変数PS1の文字列が未定義(空文字)かで判定する解答はこちらです。
$ [ -n "$PS1" ] && echo 1ppm || echo 40ppm 1ppm $ bash -c '[ -n "$PS1" ] && echo 1ppm || echo 40ppm' 40ppm