bashrcでの[-n“ $ PS1”]の目的


回答:


20

これは、シェルがインタラクティブかどうかをチェックしています。この場合、~/.bash_profileシェルが対話型の場合にのみファイルを調達します。

「このシェルはインタラクティブですか?」を参照してくださいその特定のイディオムを引用しているbashマニュアル。(また、$-特殊変数にi文字が含まれているかどうかをテストして、シェルがインタラクティブかどうかを確認することをお勧めします。これは、この問題へのより良いアプローチです。)


bashは、シェルが対話型の場合、少なくともPS1とPS2の設定を解除します。あなたが、あなた自身のためにそれを見ることができる( export PS1='abc$ '; bash -c 'echo "[$PS1]"' )だけで印刷され、[]。zshのは、少なくとも実験から、同じことをしていないようだ...いずれにせよ、意思のは、[ -n "$PS1" ]シェルが対話であるかどうかをチェックすることです。
filbranden

3
そのbash設定解除非対話(あなたの以前のコメントにタイプミス)がIMOバグですPS1は、PS1はbashの固有の変数ではありません、それはそれを設定解除一切ビジネスを持っていません。それを行う唯一のシェルです(ただし、非対話型の場合でもデフォルト値にyash設定さPS1れます)。
ステファンChazelas

1
問題のコードはbash固有のファイルにあるため、これは妥当な答えのようです。他の回答は、POSIX仕様または他のシェルのより一般的なケースに対処します。あなたは「これの目的は何ですか?」と答えました。残りの部分を適切に残しながら、質問の意図。bashが何をしているのか、そしておそらく目標を達成するためのより良い方法を知ることも良いことです。
ジェフシャラー

より信頼できる代替案が提案されていれば、この回答はより完全であると考えます(たとえば、[[ $- = *i* ]] && source ~/.bash_profile)。
Charles Duffy

@CharlesDuffy率直に言って[ -n "${PS1}" ]、にそれほど問題はないと思いますが、bashのマニュアルでも$-シェルが対話型かどうかを判断するための検査を提案/推奨していることを強調するために、回答を更新しました。回答が改善されると思います。乾杯!
filbranden

19

これは何をしますか

これは、シェルがインタラクティブであるかどうかをテストするための広範な方法です。これはbashでのみ機能し、他のシェルでは機能しないことに注意してください。したがって、(ばかげている場合は)okですが.bashrc、動作しません.profile(これはshによって読み取られ、bashはshの可能な実装の1つにすぎず、最も一般的な実装ではありません)。

なぜ機能するか(bashのみ!)

対話型シェルは、シェル変数PS1をデフォルトのプロンプト文字列に設定します。したがって、シェルがインタラクティブである場合は、PS1が設定されます(ユーザーのシェルがシェル.bashrcを削除した場合を除きます。これは、の上部でまだ発生しておらず、.bashrcとにかく愚かなことだと考えることができます)。

逆はbashにも当てはまります。bashの非インタラクティブなインスタンスはPS1開始時に設定解除されます。この動作は、(なぜでしょうbashのに固有のものであり、間違いなくバグであることを注意bash -c '… do stuff with $var…'するときに動作しないvarですPS1?)。しかし、4.4(私が書いている最新バージョン)までのすべてのバージョンのbashがこれを行います。

多くのシステムPS1が環境にエクスポートされます。多くの異なるシェルPS1が異なる構文を使用するため、これは悪い考えです(たとえば、bashのプロンプトエスケープzshのプロンプトエスケープとは完全に異なります)。しかし、実際には、それPS1が設定されていることを確認しても、シェルがインタラクティブであることを示す信頼できる指標ではないため、広く普及しています。シェルPS1は環境から継承した可能性があります。

ここで(誤用)される理由

.bashrc対話型の場合、起動時にbashが読み取るファイルです。あまり知られていない事実として、bash .bashrcはログインシェルも読み取り、bashのヒューリスティックはこれがリモートセッションであると結論づけています(bashは親がrshdまたはであるかどうかをチェックしますsshd)。この2番目のケースでは、PS1ドットファイルがまだ実行されていないため、環境で設定される可能性はほとんどありません。

ただし、コードがこの情報を使用する方法は逆効果です。

  • シェルが対話型シェルの場合、これ.bash_profileはそのシェルで実行されます。しかし.bash_profile、ログイン時のスクリプトです。セッションごとに1回だけ実行することを目的とした一部のプログラムを実行する場合があります。シェルを実行する前に、ユーザーが意図的に別の値に設定したいくつかの環境変数を上書きする可能性があります。.bash_profile非ログインシェルで実行すると混乱が生じます。
  • シェルが非対話型のリモートログインシェルの場合は、読み込まれません.bash_profile。しかし、これはロードがケースである.bash_profile非対話型ログインシェルが自動的に読み込まれないため、有用である可能性/etc/profile~/.profile

これを行う理由は、GUIを介してログインするユーザー(非常に一般的なケース)で、環境変数の設定を.bash_profileではなくに置くユーザーのためだと思います.profile。ほとんどのGUIログインメカニズムは起動します.profileが、起動しません.bash_profile(読み取りに.bash_profileは、shの代わりにセッションの起動の一部としてbashを実行する必要があります)。この構成では、ユーザーがターミナルを開くと、環境変数が取得されます。ただし、ユーザーは、非常に一般的な混乱の原因であるGUIアプリケーションで環境変数を取得しません。ここでの解決策は、環境変数を設定する.profile代わりに.bash_profileを使用することです。間のブリッジを追加.bashrcし、.bash_profileそれが解決よりも多くの問題を作成します。

代わりに何をすべきか

現在のシェルがインタラクティブかどうかをテストする簡単で移植可能な方法があります-i。オプションが有効かどうかをテストします。

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

これは、シェルが非インタラクティブである場合にのみ読み取る.bashrcために役立ちます。.profileつまり、コードが行うことの逆です!読む.profilebashの場合は、(非対話型)ログインシェルである、そしてそれは、対話型シェルの場合は、それを読んでいません。

if [[ $- != *i* && -r ~/.profile ]]; then . ~/.profile; fi

4
シェルが対話型であるかどうかをテストする良い方法であることは注目に値するかもしれない[[ -o interactive ]](kshのは、bash、zshの)またはcase $- in (*i*) ...; esac(POSIX)
ステファンChazelas

2
私のbash(バージョン4.4.12)は、PS1インタラクティブに実行しないと実際には設定が解除されているようです。テストは簡単です。PS1=cuckoo bash -c '[ -n "${PS1}" ] && echo "PS1=[${PS1}]"'何もPS1=cuckoo bash -i -c '[ -n "${PS1}" ] && echo "PS1=[${PS1}]"'出力しません$PS1が、bashスタートアップファイルのset の値を出力します(文字列 "cuckoo"は出力しません)。
FooF 2018

1
@StéphaneChazelas:POSIXでは、インタラクティブシェルを$-含むことは必要ありませんi
2018

1
Boshは、2012年以降、kshと互換性があるようにこれを行っています。変更が有効になるまでは、POSIXでは必要ありませんでした。
18

1
率直に言って、誰かがPS1をエクスポートしているときにのみ失敗するので、[ -n "${PS1}" ] 間違った呼び出しは少し行き過ぎです(あなたの答えでは、それは悪い考えだと言い、理由にさえ行きます)、それは影響しませんとにかくbashします(シェルが非対話型の場合はPS1とPS2の設定が解除されるためです)。「非推奨」などの単語を使用するか、アプローチの「制限」について話すのがよいでしょう。私はそれが完全に「間違っている」とは思わない。PS1のエクスポートに問題がある場合、それは間違いありません。とにかく、これについて詳しく説明してくれてありがとう。
filbranden

1

この奇妙な概念はbash、POSIXシェルクローンとしてではなく、Bourne Shellクローンとして始まったという事実の結果であると思われます。

その結果、POSIXインタラクティブ動作($ENVインタラクティブシェルで呼び出される)が後で追加されbash、広く知られていません。

同様の動作を許可するシェルが1つあります。これはcsh$prompt特定の値を持つcsh許可です。

$prompt not set          non-interactive shell, test $?prompt.
$prompt set but == ""    .cshrc called by the which(1) command.
$prompt set and != ""    normal interactive shell.

しかし、これはボーンシェルにもPOSIXシェルにも当てはまりません。

POSIXシェルの場合、許可される唯一の方法は、対話型シェルのコードをファイルに入れることです。

$ENV

シェル固有の名前があります。それは例えば

$HOME/.kshrc    for the korn shell
$HOME/.bashrc   for bash
$HOME/.mkshrc   for mksh
$HOME/.shrc     for the POSIX Bourne Shell

他の人々はシェルフラグ-iに言及しましたが、これは信頼できるプログラミングには使えません。POSIXは、それがset -i機能することも、インタラクティブシェル用のを$-含んでいませんi。POSIXではsh -i、シェルが対話モードになるように強制するだけです。

変数$PS1は環境からインポートできるため、非インタラクティブモードでも値が含まれる場合があります。事実bash unsetPS1いずれかの非対話型シェルでは、標準で許可されていないと、他のシェルで行われていません。

したがって、クリーンなプログラミング(を使用してもbash)は、対話型シェルのコマンドをに配置すること$HOME/.bashrcです。


0

まずDebianについて話をしますが、ほとんどの場合、Ubuntuもbashに設定しています。そして、後者は他のシステムに触れます。

シェル起動ファイルの設定には多くの意見があります。
私も私の意見はありますが、正しい設定の既存の例を示すようにします。
ファイルの例を見つけるのは非常に簡単なので、debuanを使用します。
そして、debianは頻繁に使用されるため、設定は十分にテストされています。

PS1が設定されていることを確認する目的は何ですか?

シェルがインタラクティブかどうかを確認するためだけです。

debianおよびubuntu のデフォルト/etc/profile(/ usr / share / base-files / profileから):

if [ "${PS1-}" ]; then
    if [ "${BASH-}" ] && [ "$BASH" != "/bin/sh" ]; then

ifの読み取り:ifインタラクティブ(PS1のデフォルトセット)で、bashシェルの場合(ただし、デフォルトとして機能しないsh)、PS1を特定の新しいもの(デフォルトではない)に変更します。

debianデフォルトに/etc/bash.bashrcは以下も含まれます:

# If not running interactively, don't do anything
[ -z "$PS1" ] && return

それはそれが何をするかでかなり明確です:対話型の場合、ソースしないでください(残り)。

ただし、/etc/skel/.bashrcインタラクティブシェルをテストする正しい方法のです(を使用$-)。

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac

PS1の理由と代替案が明確に示されているはずです。

正しい順序

報告している設定は避けてください。
(システム設定からbashのためのより具体的なユーザ設定()への)順序は/etc/profile/etc/bash.bashrc~/.profileそして最後に~/.bashrc。(より多くのシェルに対して)最も広範な効果を(/etc/profileルートが所有する)に置き、その後/etc/bash.bashrc(ルートも所有する)に置きますが、bashにのみ影響します。次に、で個人設定を行います。$HOME最初の設定は~/.profile、ほとんどのシェル用であり、~/.bashrc(ほぼと同等~/.bash_profile)、bash専用です。

したがって、ソース~/.bashrc~/.profile設定するのは間違っています。bashの特定のユーザー設定を、より多くのシェルに影響を与えるより一般的な設定に変換しています。この方法で行われる場合を除いて:

# ~/.profile: executed by the command interpreter for login shells
# if running bash
if [ -n "$BASH_VERSION" ]; then
    # include .bashrc if it exists
    if [ -f "$HOME/.bashrc" ]; then
    . "$HOME/.bashrc"
    fi
fi

bashが実行されていることを確認し.bashrc、その場合にのみロードします。

これはDebianからの上流の決定です。理論的根拠はここで説明されています

実際、逆の(または)のソーシング~/.profileは、特定のユースケースにすでにロードされているはずの一般的なルールを再適用するだけなので、「それほど悪くない」(私は「良い」とは言っていません)。そして、ファイルのソースがループする可能性があるので、私は良いと言っていません。サブディレクトリが親をロードするときのように、それはディレクトリループです。~/.bash_profile~/.bashrc

そして、この相互調達において、対話型シェルのチェックが意味をなしています。シェルがインタラクティブである場合にのみ~/.bashrc読み込まれますが、今度はそれが読み込まれる~/.profile(またはその逆)可能性があり、この場合はインタラクティブシェルのチェックを使用できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.