Linuxシェルのインタラクティブモードの確認とその応用

Bashスクリプトから現在のシェルが対話的かを調べる代表的な方法は、特殊パラメーター$-にiが含まれるかを確認することです。Bash公式マニュアルもこの判定を示しています。ただし、対話シェル、ログインシェル、標準入力が端末であること、利用者が目の前にいることは同じではありません。SSH、cron、systemd、CI、コンテナ、エディター内端末では組み合わせが変わります。判定の目的を「プロンプトや補完を有効にする」などへ限定し、認証や危険な操作の許可には使わないでください。

目次

Bashで推奨される$-の判定

$-には現在有効な1文字のシェルオプションが並びます。対話的なBashではiが含まれます。パターン一致を使うcaseなら、BashだけでなくBourne系シェルで読みやすく書けます。ただし、判定対象が本当にBashか、実行方法がsh script.shではないかを確認します。スクリプトの先頭で別シェルへ渡されれば、Bash固有の前提は成立しません。

case $- in
  *i*) printf '%s\n' 'interactive Bash shell' ;;
  *)   printf '%s\n' 'non-interactive shell' ;;
esac

Bashの[[ ]]を使うなら、[[ $- == *i* ]]でも判定できます。これはBash、Korn shell、zshなどで構文や細部が異なり、POSIXのshスクリプトにはそのまま持ち込みません。ライブラリとしてsourceされるファイルでは、呼び出し元のシェルやオプションを継承します。「このファイルが端末から実行された」ではなく「現在のシェル状態」を見ている点が重要です。

if [[ $- == *i* ]]; then
  printf '%s\n' 'interactive'
else
  printf '%s\n' 'non-interactive'
fi

PS1による判定との違い

Bash公式マニュアルには、PS1が設定されているかを調べる方法も示されています。対話シェルはPS1を設定し、非対話シェルでは通常設定しません。しかし、環境や起動ファイルでPS1を手動設定できるため、$-のi確認の方が直接的です。またset -uで未設定変数をエラーにするスクリプトでは、${PS1-}のように未設定を安全に扱う必要があります。

if [[ -n ${PS1-} ]]; then
  printf '%s\n' 'PS1 is set'
fi

PS1はプロンプト文字列であり、空に設定された対話環境も作れます。PS1に色や制御シーケンスが含まれていても、それをログへ出力したり、コマンドとして再評価したりしません。環境変数は信頼できない入力として扱います。

[ -t 0 ]は端末接続の判定

test -t FDまたは[ -t 0 ]は、ファイル記述子が端末を参照しているかを調べます。0は標準入力、1は標準出力、2は標準エラーです。これはシェルの対話フラグとは別の質問です。たとえば、対話的なシェルでも出力だけをファイルへリダイレクトすれば-t 1は偽になり得ます。非対話スクリプトでも端末を標準入力として受け取る起動方法があります。

if [[ -t 0 && -t 1 ]]; then
  printf '%s\n' 'stdin and stdout are terminals'
else
  printf '%s\n' 'at least one stream is redirected or piped'
fi

色付き表示、進捗バー、ページャーの起動可否を決めたい場合は、対話性より出力先が端末かを調べる方が目的に合います。一方、入力を質問してよいかは標準入力の端末性、非対話モードを明示するオプション、タイムアウト、既定値を組み合わせます。単に$-へiがあるからといって、利用者が応答できるとは限りません。

interactiveとloginは別の軸

ログインシェルはログインセッションとして起動されたシェルで、対話的かどうかとは独立しています。対話ログイン、対話非ログイン、非対話ログイン、非対話非ログインの組み合わせがあり得ます。Bashは起動形態に応じて/etc/profile、~/.bash_profile、~/.bash_login、~/.profile、~/.bashrc、BASH_ENVなど異なるファイルを読みます。設定が端末では動くのにcronで動かない問題は、対話性だけでなく、起動ファイル、PATH、作業ディレクトリ、環境変数の差を調べます。

  • SSHで通常ログイン:対話ログインシェルになる構成が多いが、SSH設定と起動方法に依存する。
  • GUI端末で新しいタブ:対話非ログインシェルになる構成が多い。
  • bash script.sh:通常は非対話非ログインで、対話用~/.bashrcを自動では読まない。
  • bash -i:入力や出力の接続にかかわらず対話モードを強制するため、テスト以外では副作用に注意する。
  • bash –login -c command:非対話ログインとして起動でき、ログイン用設定を読む点に注意する。

起動ファイルでの実用的な使い方

~/.bashrcには、対話専用設定の前で非対話なら戻る防御を置く構成があります。目的はエイリアス、補完、プロンプト、履歴、端末制御を非対話処理へ持ち込まないことです。ただし、既存のディストリビューション設定を上書きせず、ファイル全体の読み込み順を確認します。非対話処理にも必要な環境変数をreturnより後ろに置くと、SSHのリモートコマンドやツールが動かなくなることがあります。共有設定と対話設定を分ける方が明確です。

case $- in
  *i*) ;;
  *) return ;;
esac

# Interactive-only prompt and completion settings follow.

この断片はsourceされる~/.bashrc向けです。独立した実行スクリプトでトップレベルのreturnを使うとエラーになるため、用途を取り違えません。終了させるexitを~/.bashrcへ無条件に置くと、親のログインやSSHセッションを閉じる可能性があります。

起動ファイルで標準出力を汚さない

~/.bashrcや~/.profileから無条件にechoすると、scp、sftp、rsync、リモートコマンド、IDE連携、JSONを返す自動処理へ余計な文字が混ざることがあります。メッセージを出すなら対話性と端末性の両方を確認し、標準エラーへ出す必要があるかも検討します。デバッグ出力は恒久的に残さず、ログファイルへも秘密情報や環境変数全体を出しません。

SSHでは擬似端末の有無も確認する

SSHは通常のリモートログイン、単一コマンド実行、擬似端末を強制する-t、割り当てない-Tなどで状態が変わります。ssh host commandは一般に非対話シェルとしてコマンドを実行しますが、サーバー設定やコマンドにより起動経路は異なります。擬似端末があることとBashの対話フラグは同じではありません。自動処理は端末に依存するプロンプトを出さず、必要な入力は引数、標準入力、秘密情報管理から明示的に受け取ります。

cron、systemd、CIで失敗する典型原因

  • PATHが短い:コマンドの絶対パスまたはジョブ用の明示PATHを使い、対話用設定に依存しない。
  • 作業ディレクトリが違う:スクリプト自身で安全な絶対パスを決め、相対パスを暗黙に使わない。
  • 環境変数がない:必要値だけをジョブ定義から渡し、シェル履歴や対話設定から継承しない。
  • プロンプト待ち:非対話オプションを使い、確認が必要な操作は事前承認と別工程にする。
  • 端末制御文字:色、ページャー、進捗表示を無効にし、機械可読な出力を選ぶ。
  • 別シェルで実行:shebang、実行権限、ジョブ定義の呼び出し方を確認する。

判定をセキュリティ境界にしない

利用者はbash -iで対話フラグを付けられ、端末も擬似端末として割り当てられます。したがって、対話的なら管理者操作を許可する、端末なら秘密を表示する、非対話なら入力検証を省略するといった設計は危険です。権限はOSのユーザー、グループ、ポリシー、認証、承認によって決めます。対話性は表示形式やユーザー体験を調整するための状態にすぎません。

テストマトリクスを用意する

シェルスクリプトを配布する前に、直接実行、source、パイプ入力、出力リダイレクト、SSHリモートコマンド、cronまたはsystemd相当の空に近い環境で試します。各ケースで$-、-t 0、-t 1、ログイン状態、読み込まれた設定、終了状態を記録します。ただし、本番の秘密を環境ダンプへ含めません。期待する動作を表にすると、対話判定の条件が目的に合っているかレビューできます。

実装の選び方

プロンプトや補完を出すかは$-のi、色やページャーを使うかは-t 1、質問入力を許すかは-t 0と明示オプション、ログイン用初期化が必要かは起動方法というように、質問ごとに判定を分けます。一つの変数だけですべてを推測しないことがポイントです。Bash以外も対象なら、シェルごとの公式仕様を確認し、機能検出と明示設定を優先してください。

公式情報・参考資料

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次