GNU/Linux >> Linux の 問題 >  >> Linux

Bashrcが現在のシェルがインタラクティブであるかどうかをチェックするのはなぜですか?

Archのインストールでは、/etc/bash.bashrc および/etc/skel/.bashrc 次の行が含まれています:

# If not running interactively, don't do anything
[[ $- != *i* ]] && return

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

man bashによると ただし、非対話型シェルはこれらのファイルを読み取ることさえしません:

   When  bash  is  started  non-interactively,  to run a shell script, for
   example, it looks for the variable BASH_ENV in the environment, expands
   its  value if it appears there, and uses the expanded value as the name
   of a file to read and execute.  Bash behaves as if the  following  com‐
   mand were executed:
          if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi
   but  the value of the PATH variable is not used to search for the file‐
   name.

私が正しく理解していれば、*.bashrc BASH_ENVの場合にのみファイルが読み取られます それらを指すように設定されています。これは偶然には起こり得ないことであり、誰かがそれに応じて変数を明示的に設定した場合にのみ発生します。

これにより、スクリプトがユーザーの.bashrcをソースする可能性が失われるようです。 BASH_ENVを設定することで自動的に 、便利なもの。明示的に指示されない限り、bashが非対話的に実行されたときにこれらのファイルを読み取ることは決してないので、デフォルトの*bashrcを実行するのはなぜですか。 ファイルはそれを許可しませんか?

承認された回答:

これは私が数週間前にここに投稿しようとしていた質問です。 terdonのように 、.bashrc インタラクティブなBashシェルのみをソースとしているため、.bashrcは必要ありません。 インタラクティブシェルで実行されているかどうかを確認します。紛らわしいことに、すべて 私が使用しているディストリビューション(Ubuntu、RHEL、Cygwin)には、ある種のチェック($-のテスト)がありました。 または$PS1 )現在のシェルがインタラクティブであることを確認します。カーゴカルトプログラミングが好きではないので、.bashrcでこのコードの目的を理解することにしました。 。

Bashにはリモートシェル用の特別なケースがあります

この問題を調査したところ、リモートシェルであることがわかりました。 扱いが異なります。非対話型のBashシェルは通常、~/.bashrcを実行しませんが 起動時のコマンドでは、シェルがリモートシェルデーモンによって呼び出されたときに特別なケースが作成されます:

Bashは、リモートシェル
デーモン(通常はrshd)によって実行される場合のように、ネットワーク接続に接続された標準入力
で実行されているかどうかを判断しようとします。 、またはセキュアシェルデーモンsshd 。 Bashが
この方法で実行されていると判断した場合、そのファイルが存在し、読み取り可能であれば、〜/.bashrcから
コマンドを読み取って実行します。
shとして呼び出された場合、これは行われません。 。 --norc オプションを使用して、この動作を禁止できます。
および--rcfile オプションを使用して別のファイルを強制的に読み取ることができますが、
どちらもrshd また、sshd 通常、これらのオプションを使用してシェルを呼び出すか、
それらを指定できるようにします。

リモートの.bashrcの先頭に以下を挿入します 。 (.bashrcの場合 .profileによって供給されます または.bash_profile 、テスト中にこれを一時的に無効にします):

echo bashrc
fun()
{
    echo functions work
}

次のコマンドをローカルで実行します。

$ ssh remote_host 'echo $- $0'
bashrc
hBc bash
  • いいえi $-で シェルが非対話型であることを示します 。
  • 先頭の-はありません $0で シェルがログインシェルではないことを示します 。

リモートの.bashrcで定義されたシェル関数 実行することもできます:

$ ssh remote_host fun
bashrc
functions work

~/.bashrcに気づきました のみ sshの引数としてコマンドが指定されている場合に供給されます 。これは理にかなっています:sshの場合 通常のログインシェル.profileを開始するために使用されます または.bash_profile 実行されます(および.bashrc これらのファイルのいずれかによって明示的に行われた場合にのみソースされます。

関連:Php:current —配列内の現在の要素を返します

.bashrcを使用することで得られる主なメリット (非対話型の)リモートコマンドを実行するときに得られるのは、シェル関数を実行できるということです。ただし、一般的な.bashrcのほとんどのコマンド インタラクティブシェルにのみ関連します。たとえば、シェルがインタラクティブでない限り、エイリアスは展開されません。

リモートファイル転送が失敗する可能性があります

rshの場合、これは通常問題にはなりません。 またはssh 対話型ログインシェルを開始するため、または非対話型シェルを使用してコマンドを実行する場合に使用されます。ただし、問題になる可能性があります rcpなどのプログラムの場合 、scp およびsftp リモートシェルを使用する データ転送用。

scpを使用すると、リモートユーザーのデフォルトシェル(Bashなど)が暗黙的に開始されることがわかりました。 指図。マニュアルページにはこれについての言及はありません。scpについての言及だけです。 sshを使用します そのデータ転送のため。これは、 .bashrcの場合にという結果になります 標準出力に出力するコマンドが含まれている場合、ファイル転送は失敗します たとえば、scpはエラーなしで失敗します。

なぜscp およびsftp 失敗

SCP(セキュアコピー)とSFTP(セキュアファイル転送プロトコル)には、転送されるファイルに関する情報を交換するためのローカルエンドとリモートエンド用の独自のプロトコルがあります。リモートエンドからの予期しないテキストは(誤って)プロトコルの一部として解釈され、転送は失敗します。カタツムリの本からのFAQによると

ただし、よくあることは、サーバー上の
システムまたはユーザーごとのシェル起動ファイル(.bashrc)のいずれかにステートメントがあることです。 、.profile/etc/csh.cshrc.login 、など)ログイン時にテキストメッセージを出力します。
人間が読むことを目的としています(fortuneなど)。 、echo "Hi there!" など)。

このようなコードは、ttyがある場合にのみ、インタラクティブログインで出力を生成する必要があります。 標準入力に接続されています。このテストを行わない場合は、
これらのテキストメッセージが属していない場所に挿入されます。この場合、
scp2間のプロトコルストリームを汚染します。 / sftp およびsftp-server

シェルの起動ファイルがまったく関連している理由は、 sshdであるためです。 ユーザーに代わってプログラムを起動するときに、ユーザーのシェルを使用します (例:/ bin / sh -c「コマンド」を使用)。これはUnixの伝統であり、
利点があります:

  • リモートコマンドを実行すると、ユーザーの通常の設定(コマンドエイリアス、環境変数、umask、
    など)が有効になります。
  • アカウントのシェルを/bin/ falseに設定して無効にする一般的な方法は、
    何らかの理由で認証が誤って成功した場合でも、所有者がコマンドを実行できないようにします。

SCPプロトコルの詳細

SCPの動作の詳細に興味がある人のために、リモート側でおしゃべりなシェルプロファイルを使用してscpを実行する方法の詳細を含むSCPプロトコルの動作方法に興味深い情報を見つけました。 :

たとえば、これを
リモートシステムのシェルプロファイルに追加すると発生する可能性があります:

エコー「」

なぜそれがハングするのですか?これは、scp ソース mode
は、最初のプロトコルメッセージの確認を待ちます。バイナリ
0でない場合は、リモートの問題の通知であると想定し、新しい行が到着するまで
さらに多くの文字がエラーメッセージを形成するのを待ちます。
最初の行の後に別の新しい行を印刷しなかったため、ローカルのscp ちょうど
ループにとどまり、read(2)でブロックされます 。その間、シェルの
プロファイルがリモート側で処理された後、scp シンクモードで開始されました。
これもread(2)でブロックされます 、データ転送の開始を示すバイナリゼロを待機しています

結論/TLDR

典型的な.bashrcのほとんどのステートメント rshを使用してリモートコマンドを実行する場合ではなく、インタラクティブシェルでのみ役立ちます。 またはssh 。このようなほとんどの状況では、シェル変数、エイリアスの設定、関数の定義は望ましくありません。任意のテキストを出力します。 scpなどのプログラムを使用してファイルを転送する場合、標準化することは積極的に有害です。 またはsftp 。現在のシェルが非対話型であることを確認した後に終了するのが、.bashrcの最も安全な動作です。 。


Linux
  1. なぜ誰もTrueBourneShellを/bin/ shとして使用しないのですか?

  2. .bashrcを編集した後、プロンプトでGhostsを取得しましたか?

  3. Bashの正規表現が変数であり、直接ではない場合にのみ機能するのはなぜですか?

  1. 現在のシェルから.bashrcを再生成しますか?

  2. このシェル パイプラインが終了するのはなぜですか?

  3. 構文 |&はシェル言語で何を意味しますか?

  1. Bash(Linux シェル)で Ctrl + V が貼り付けられないのはなぜですか?

  2. 「bin」ユーザーにログインシェルが必要なのはなぜですか?

  3. setuid ビットの動作に一貫性がないのはなぜですか?