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
_が実行されているかどうかを確認する必要がないはずです。インタラクティブシェル。混乱して、all私が使用するディストリビューション(Ubuntu、RHEL、およびCygwin)には、ある種のチェック(テスト_$-
_または_$PS1
_)がありました)現在のシェルがインタラクティブであることを確認します。 貨物カルトプログラミング が嫌いなので、このコードの目的を_.bashrc
_で理解することにしました。
この問題を調査した結果、リモートシェルの扱いが異なることがわかりました。非インタラクティブな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
がない場合は、シェルが non-interactive であることを示します。-
_の先頭に_$0
_がない場合は、シェルが login Shell ではないことを示します。リモート_.bashrc
_で定義されたシェル関数も実行できます。
_$ ssh remote_Host fun
bashrc
functions work
_
ssh
の引数としてコマンドが指定されている場合、_~/.bashrc
_が only をソースとしていることに気付きました。これは理にかなっています。ssh
を使用して通常のログインシェルを開始すると、_.profile
_または_.bash_profile
_が実行されます(および_.bashrc
_は、これらのファイルのいずれかによって明示的に実行された場合にのみ供給されます)。
(非インタラクティブ)リモートコマンドを実行するときに_.bashrc
_ソースを取得することで得られる主な利点は、シェル関数を実行できることです。ただし、一般的な_.bashrc
_のほとんどのコマンドはインタラクティブシェルにのみ関連しています。たとえば、シェルがインタラクティブでない限り、エイリアスは展開されません。
rsh
またはssh
を使用してインタラクティブログインシェルを起動する場合、または非インタラクティブシェルを使用してコマンドを実行する場合、これは通常問題ではありません。ただし、データを転送するためにリモートシェルを使用するrcp
、scp
、sftp
などのプログラムでは、問題になる可能性があります。
scp
コマンドを使用すると、リモートユーザーのデフォルトのシェル(Bashなど)が暗黙的に開始されることがわかります。マンページにはこれについての言及はありません。scp
がデータ転送にssh
を使用しているという言及のみです。これにより、_.bashrc
_に標準出力に出力するコマンドが含まれている場合、ファイル転送が失敗します、たとえば scpはエラーなしで失敗します 。
15年前のこの関連するRed Hatバグレポートも参照してください scpは、/ etc/bashrcにechoコマンドがあると壊れます (最終的にWONTFIX
として閉じられました)。
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の実行に関する詳細が含まれています側?:
たとえば、これをリモートシステムのシェルプロファイルに追加した場合に発生する可能性があります。
エコー ""
なぜハングするのですか?これは、sourceモードの
scp
が最初のプロトコルメッセージの確認を待機する方法に由来します。バイナリ0でない場合は、リモートの問題の通知であると想定し、新しい行が到着するまで、さらに多くの文字がエラーメッセージを形成するのを待ちます。最初の行の後に別の新しい行を印刷しなかったので、ローカルのscp
はループにとどまり、read(2)
でブロックされます。その間、シェルプロファイルがリモート側で処理された後、シンクモードのscp
が開始されました。これもread(2)
をブロックし、データ転送の開始を示すバイナリゼロを待機しています。
一般的な_.bashrc
_のステートメントのほとんどは、インタラクティブシェルでのみ役立ちます。rsh
またはssh
を使用してリモートコマンドを実行する場合は役に立ちません。このような状況のほとんどでは、シェル変数、エイリアス、関数の定義は望ましくありません。また、scp
やsftp
などのプログラムを使用してファイルを転送する場合、 any text を標準出力に出力することは非常に危険です。現在のシェルが非インタラクティブであることを確認した後に終了するのが_.bashrc
_の最も安全な動作です。
マニュアルページでは、bash
も非インタラクティブリモートシェルの.bashrc
をソースとしていることを無視しています。
ssh hostname command
http://git.savannah.gnu.org/cgit/bash.git/tree/Shell.c#n101
COMMAND EXECUTE BASHRC
--------------------------------
bash -c foo NO
bash foo NO
foo NO
rsh machine ls YES (for rsh, which calls 'bash -c')
rsh machine foo YES (for Shell started by rsh) NO (for foo!)
echo ls | bash NO
login NO
bash YES
http://git.savannah.gnu.org/cgit/bash.git/tree/Shell.c#n105
/* If we were run by sshd or we think we were run by rshd, execute
~/.bashrc if we are a top-level Shell. */
if ((run_by_ssh || isnetconn (fileno (stdin))) && Shell_level < 2)
{
maybe_execute_file (SYS_BASHRC, 1);
maybe_execute_file (bashrc_file, 1);
慣例により、.bashrc
は、ユーザーがシェルのカスタマイズ構成を格納する場所です。
これらのカスタマイズ構成は、環境変数、エイリアス、派手なプロンプトにすることができます。非インタラクティブシェルでは、これらの不足分は意味がありません。さらに、非対話型シェルは多くのコンテキストで呼び出される可能性があり、これらの環境変数が偽陰性のケースを引き起こしたり、セキュリティが脆弱になったりする可能性があるかどうかはわかりません。
最も近い例は次のようなエイリアスです。
alias cp='cp -i'
次に、非インタラクティブシェルを永久にハングさせます。
したがって、チェックは.bashrc
の上部で実行され、問題が発生しないことを確認します。
シェルは非インタラクティブloginシェルとして呼び出すことができるため、明示的に*bashrc
のソーシングをブロックしても意味がありません。
シェルが 非対話型ログインシェルと呼ばれる の場合、/etc/profile
をソースにし、~/.bash_profile
、~/.bash_login
、および~/.profile
で最初に見つかったシェルをソースします。
Bashがインタラクティブログインシェルまたは--loginオプションの非インタラクティブシェルとして呼び出されると、最初に/ etc/profileファイル(存在する場合)。そのファイルを読み取った後、〜/ .bash_profile、〜/ .bash_login、および〜/ .profileをこの順序で検索し、存在し、読み取り可能な最初のコマンドからコマンドを読み取って実行します。
これらのファイルが.bashrc
自体をソースすることを妨げるものは何もないため、.bashrc
内でチェックを行う方が安全であり、物事を単純化します。