web-dev-qa-db-ja.com

bashrcでの[-n "$ PS1"]の目的

[ -n "$PS1" ][ -n "$PS1" ] && source ~/.bash_profile;の目的は何ですか?この行は、ドットファイルの.bashrcrepo に含まれています。

10
shotes

これは、シェルがインタラクティブかどうかを確認しています。この場合、~/.bash_profileシェルがインタラクティブな場合はファイル。

特定のイディオムを引用しているbashマニュアルの "Is this Shell Interactive?" を参照してください。 (また、$-特殊変数にはi文字が含まれています。これは、この問題へのより良いアプローチです。)

20
filbranden

これは何をしますか

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

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

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

逆はbashに当てはまります。bashの非対話型インスタンスは、開始時にPS1を設定解除します。この動作はbashに固有のものであり、間違いなくバグであることに注意してください(varbash -c '… do stuff with $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からread .profileで、シェルが非インタラクティブの場合にのみ役立ちます。つまり、コードの動作が逆になります。 bashが(非対話型)ログインシェルの場合は.profileを読み取り、対話型シェルの場合は読み取らないでください。

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

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

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

同様の動作を許可するシェルが1つあります。これはcshであり、c [は$Promptに特定の値があることを許可します。

$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は環境からインポートできるため、非インタラクティブモードでも値が含まれる場合があります。非対話型シェルのbashunsets PS1は、標準では許可されておらず、他のシェルでは実行されません。

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

1
schily

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

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

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

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

debian とubuntu(/ usr/share/base-files/profileから)のデフォルト_/etc/profile_:

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

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

default _/etc/bash.bashrc_ in debian には以下も含まれます:

_# 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_であり、bashのみに固有の_~/.bashrc_(_~/.bash_profile_とほぼ同等)です。

したがって、_~/.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_ in _~/.bash_profile_(または_~/.bashrc_)は、特定のユースケースに既にロードされているはずの一般的なルールを再適用するだけなので、「悪い」(「良い」とは言っていません)。そして、ファイルのソースがループする可能性があるので、私は良いと言っていません。サブディレクトリが親をロードするときのように、それはディレクトリループです。

そして、インタラクティブシェルのチェックが意味をなすのは、このクロスソースです。シェルがインタラクティブな場合にのみ_~/.bashrc_が読み込まれますが、次に_~/.profile_(またはその逆)が読み込まれる可能性があり、この場合はインタラクティブシェルのチェックを使用できます。

0
Isaac