シェルがログイン/インタラクティブ/バッチであるかどうかを確認する方法


145

インタラクティブ、ログイン、バッチシェルの違いを理解していると思います。詳細については、次のリンクを参照してください。

私の質問は、対話型、ログイン、またはバッチシェルを使用している場合、コマンド/条件を使用してどのようにテストできますか?

私は、(返すコマンドまたは条件を探していますtruefalse)、私はまた、if文の上に置くことができること。例えば:

if [[ condition ]]
   echo "This is a login shell"
fi

3
さらに別の質問があります:STDINおよび/またはSTDOUTはtty(端末)またはパイプ(ファイルまたはプロセス)に接続されていますか?これは、以下のコメントのいくつかで説明されているように、関連するが別個のテストです。
マークハドソン14年

回答:


162

bashタグにシェルがリストされていないため、シェルなどを想定しています。

対話型シェルを使用しているかどうかを確認するには:

[[ $- == *i* ]] && echo 'Interactive' || echo 'Not interactive'

ログインシェルにいるかどうかを確認するには:

shopt -q login_shell && echo 'Login shell' || echo 'Not login shell'

「バッチ」とは、「非対話型」を意味すると想定しているため、対話型シェルのチェックで十分です。


12
以下の場合zsh:ユーザー、ログインシェルのチェックをして行うことができますif [[ -o login ]] ...
CHB

1
「ユーザー」が「cron」に対してプログラムを実行したかどうかを知りたい場合。[TERM] == "ダム"] &&クーロンで実行」エコー。
エリックAronesty

10
@ErikAronestyすべてのダム端末がcronセッションではありません。
クリスダウン

2
「タグにシェルがリストされていないため、bashシェルなどを想定しています。」–このステートメントのロジックは本当に美しいです。:)
マイケルルバルビエグリュネヴァルド

2
@antonioこれは、引用が間違っているため$-に、現在のシェルで展開されているためです。:あなたは完全な表現の周りに単一引用符を使用する場合は、正しい結果を取得しますbash -c '[[ $- == *i* ]] && echo "Interactive" || echo "Not interactive"'
クリス・ダウン

33

Bourneスタイルのシェルでは、iオプションはシェルがインタラクティブかどうかを示します。

case $- in
  *i*) echo "This shell is interactive";;
  *) echo "This is a script";;
esac

ログインシェルをテストするための移植性があり、完全に信頼できる方法はありません。Kshとzshがに追加さl$-ます。Bashはlogin_shellオプションを設定します。このオプションはで照会できますshopt -q login_shell。移植可能:呼び出し元が引数ゼロ(通常は実行可能ファイルの名前またはパス)にプレフィックスを追加したため、:で$0始まる-シェルがログインシェルであることを通常知っているかどうかをテストします-。これは、ログインシェルを呼び出すシェル固有の方法の検出に失敗します(例:)ash -l


(...)呼び出し元のため –このフラグメントには何か不足していると思います。
ピョートルドブロゴスト

開始方法に関係なく$0常に開始するのが理想的です-。ただし、少なくとも1つの例外があります。これは、ログインシェルであると想定されている場合でも、bashでは必ずしも当てはまりません。ボックスで試してみてください:invoke bash --login$0それでもを読み取りますbash
ウィラワンプルワント

@WirawanPurwantoあなたのコメントを理解したかどうかわかりません。それは私が最後の文で書いたものではありませんか?
ジル

@Gilles:あなたは正しいです。申し訳ありませんが、最後の文を逃しました。
ウィラワンプルワント

24

魚の殻

fish他のユーザーがこのページを見つけた場合の答えは次のとおりです。

if status --is-interactive
    # ...
end

if status --is-login
    # ...
end

echo "darn, I really wanted to have to use globs or at least a case statement"

Fishドキュメント:初期化


1
-1不要な編集。
ニックバスティン

6
@NickBastinのコメントに疑問を抱く人がいたら、彼は公正なポイントを持っていたので、編集しました。元の量のスナーキネスは半分になりました。
-ohspite

18

csh / tcsh

以下のためにcshtcsh私は私の中で次のようしている.cshrcファイル:

if($?prompt) then               # Only interactive shells set $prompt
    ...
endif

特に、ログインシェルのtcsh変数loginshが設定されます。

if($?loginsh) then              # A login shell..
    ...
endif

tcshまたshlvl、ネストされたシェルの数に設定される変数があり、ログインシェルの値は1です。)


2
PS1対話型シェルのテストには機能しません。ほとんどの場合、インタラクティブに設定されますが、設定を解除できます。多くのシステムにはexport PSinが同梱されて/etc/profileいるため、非常に頻繁に非対話型シェルに設定されます。
ジル

@Gilles補正や編集をありがとう
アンドリュー・スタイン

17

別の方法は、次の結果を確認することです tty

if [ "`tty`" != "not a tty" ]; then

10
...または[ -t 0 ]STDINがttyかどうかをテストするために使用します。必要に応じて1(STDOUT)または2(STDERR)を使用することもできます。
derobert

@derobert-何か新しいことを見せてくれてありがとう
エイドリアンコーニッシュ

10
これは別のテストです。入力が端末である非対話型シェルを使用することは可能です(端末でスクリプトを実行するときはいつでも!)。また、(まれではありますが)対話型シェルが端末からではなく入力を受け取ることができます。
ジル

@Gillesは、シェルが対話型であり、閉じて子disownを残して生きている場合、変更されていないが、ttyもはや対話型ではないことを知るために最善の働きを$-しました。私は今でも最善のアプローチが何なのか戸惑っています。
アクエリアスパワー14

5
@AquariusPower次に、テストするのは対話型シェルではなく、標準入力が端末かどうかです。を使用し[ -t 0 ]ます。PS前のコメントで、「強い相関関係があります」と書きました。「非常に一般的な、開始されたスクリプトなどのケースは別として」忘れてしまい#!/bin/shました。
ジル14

8

UNIX / Linuxには、ターミナルにいるかどうかを確認するコマンドがあります。

if tty -s
then
echo Terminal
else
echo Not on a terminal
fi

1
これdashも機能します。
ケンシャープ

7

stdinが端末であるかどうかを確認できます。

if [ -t 0 ]
then
    echo "Hit enter"
    read ans
fi

3

スクリプトが対話型シェルで実行されるか、非対話型シェルで実行されるかを確認するには、$PS1変数に保存されているプロンプトの存在をスクリプトで確認します。

if [ -z $PS1 ] # no prompt?
### if [ -v PS1 ]   # On Bash 4.2+ ...
then
  # non-interactive
  ...
else
  # interactive
  ...
fi

ここで学んだこと:https : //www.tldp.org/LDP/abs/html/intandnonint.html


1

i探すのに適切なオプションではありません。-iそれ以外の場合は非対話型のシェルを強制的に対話型にすることです。正しい自動有効化オプションはですが-s、残念ながらBashはこれを正しく処理しません。

$-含むs(これは自動アクティブ化が許可されている)かどうかi(これは自動アクティブ化は許可されていないが、正式-iにはシェルのコマンドラインオプションにのみ結合されている)を確認する必要があります。


1
sシェルが対話型かどうかではなく、標準入力からコマンドを読み取る場合です。対話型シェルは必ずしもstdinからコマンドを読み取るとは限りません(zsh -i < /dev/nullここではzshが例外のようですが、試してみてください)。また、シェルはstdinからコマンドを読み込んでいて、インタラクティブではない(sh < fileまたはのようなecho 'echo "$1"' | sh -s foo bar)場合があります。
ステファンシャゼル

2
私が指摘したかったのは、元のBourne Shellの$-に 'i'が含まれていないことです。たとえそれがインタラクティブであることを意図していてもです。
気違い

わかりましたが、U&Lでは、「シェル」は現代のシェルを指す傾向があります。Bourneシェルは一般にリリックと見なされ、独自のバリアントは、明示的にしない限り、人々があなたが話していることを知ることを期待するほど主流ではありません。言及され[[...]]た質問は、ksh / bash / zshを意味します。Bourneシェルではチェックインが機能しないという点に注意しください。しかし、それでもチェックは確実に機能しません。またはを確認することもできます。でも、そのようにはコーナーケースにだまされるだろうi$-s[ -t 0 ]iecho 'exec < /dev/tty; that-check' | sh'
ステファンChazelas

Solaris 10までのSolarisにはオリジナルのBourne Shellが付属しており、シルにもaproxが含まれています。SVr4以降、シェルに存在することがわかっている10個のバグ。したがって、Bourne Shellにヒントを追加することは、あなたが生きているかもしれないので、いやらしいことではありません。反対側のzshは十分な互換性がありません。たとえば、zshで「configure」を実行しようとすると失敗するため、zshを指すように/ bin / shを設定するように注意してください。ところで:Bourne Shellは、対話型と判断した場合に備えて、デフォルトで-iを設定します。
気味悪い

3
POSIXは$-contains i(sを必要とするようです)を必要としないように見えるので、austin-group MLについて質問します。
ステファンシャゼル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.