これは、数週間前にここに投稿しようとしていた質問です。同様terdon、私がいることを理解.bashrc
は必要ないはずですので、唯一の対話型のBashシェルのために供給され.bashrc
、それは対話型シェルで実行されているかどうかを確認します。紛らわしいことに、私が使用するすべてのディストリビューション(Ubuntu、RHEL、およびCygwin)には、現在のシェルが対話型であることを確認するための何らかのタイプのチェック(テスト$-
または$PS1
)がありました。私はカーゴカルトプログラミングが好きではないので、私のコードでこのコードの目的を理解し始めました.bashrc
。
Bashにはリモートシェル用の特別なケースがあります
この問題を調査した後、リモートシェルの扱いが異なることを発見しました。非対話型のBashシェルは通常~/.bashrc
、起動時にコマンドを実行しませんが、シェルがリモートシェルデーモンによって呼び出されると特別なケースが作成されます。
Bashは、通常はリモートシェルデーモン(通常rshd
はセキュアシェルデーモン)によって実行されるときのように、ネットワーク接続に接続された標準入力で実行されているかどうかを判断しようとしますsshd
。この方法で実行されているとBashが判断した場合、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
- No
i
in $-
は、シェルが非対話型であることを示します。
- リードなし
-
では$0
シェルがないことを示していないログインシェル。
リモートで定義されたシェル関数.bashrc
も実行できます。
$ ssh remote_host fun
bashrc
functions work
私は気づい~/.bashrc
ているだけコマンドがための引数として指定されたときにソースssh
。これは理にかなっています:ssh
通常のログインシェルを開始するために使用される.profile
か.bash_profile
、実行されるとき(および.bashrc
これらのファイルのいずれかによって明示的に実行された場合にのみソースされます)。
.bashrc
(非対話型)リモートコマンドを実行するときにソースを取得することでわかる主な利点は、シェル関数を実行できることです。ただし、典型的なコマンドのほとんどは.bashrc
対話型シェルにのみ関連しています。たとえば、シェルは対話型でない限りエイリアスは展開されません。
リモートファイル転送が失敗する可能性があります
これは通常、対話型ログインシェルを起動するために使用される場合、rsh
またはssh
コマンドを実行するために非対話型シェルが使用される場合は問題になりません。しかし、それは問題になる可能性がありますのようなプログラムのためrcp
、scp
およびsftp
それが使用するリモートシェルをデータを転送します。
scp
コマンドを使用すると、リモートユーザーのデフォルトシェル(Bashなど)が暗黙的に起動されることがわかりました。manページにはこれに関する言及はありません。データ転送にscp
使用する言及のみssh
です。これには、標準出力に出力するコマンドが含まれている場合.bashrc
、ファイル転送が失敗するという結果が生じます。たとえば、
scpはエラーなしで失敗します。
15年前のこの関連するRed Hatのバグレポートも参照してください。/etc/bashrcにechoコマンドがあるとscpが壊れます(最終的にとして閉じられましたWONTFIX
)。
なぜscp
とsftp
失敗
SCP(セキュアコピー)とSFTP(セキュアファイル転送プロトコル)には、転送されるファイルに関する情報を交換するためのローカルエンドとリモートエンド用の独自のプロトコルがあります。リモートエンドからの予期しないテキストは(間違って)プロトコルの一部として解釈され、転送は失敗します。Snail BookのFAQによると
何が頻繁に起こる、しかし、サーバー上のシステムやユーザごとのシェル起動ファイルのいずれかでのステートメント(があるということです.bashrc
、.profile
、
/etc/csh.cshrc
、.login
、など)は、ヒト(等によって読まれることを意図し、ログインに出力テキストメッセージは、fortune
、echo "Hi there!"
、等。)。
このようなコードは、tty
標準入力に接続されている場合にのみ、対話型ログインで出力を生成する必要があり
ます。このテストを行わない場合、これらのテキストメッセージが属していない場所に挿入されます。この場合、scp2
/ sftp
との間のプロトコルストリームを汚染しますsftp-server
。
シェルスタートアップファイルがまったく関連する理由はsshd
、ユーザーの代わりにプログラムを起動するときにユーザーのシェル
を使用するためです(たとえば、/ bin / sh -c "command"を使用)。これはUnixの伝統であり、利点があります。
- ユーザーの通常のセットアップ(コマンドエイリアス、環境変数、umaskなど)は、リモートコマンドの実行時に有効になります。
- アカウントのシェルを/ bin / falseに設定して無効にする一般的な方法では、何らかの理由で認証が誤って成功した場合、所有者はコマンドを実行できません。
SCPプロトコルの詳細
SCPの動作方法の詳細に興味がある人のために、SCPプロトコルの動作方法に興味深い情報を見つけました。これには、リモート側で対話型シェルプロファイルを使用してscpを実行する方法の詳細が含まれていますか?:
たとえば、これはリモートシステムのシェルプロファイルにこれを追加すると発生する可能性があります。
エコー ""
なぜハングするのですか?これはscp
、ソースモードで最初のプロトコルメッセージの確認を待機する方法に由来します。バイナリ0でない場合は、リモートの問題の通知であると想定し、新しい行が到着するまでエラーメッセージを形成するためにさらに文字を待機します。最初の行の後に別の新しい行を印刷しなかったため、ローカルscp
はループ内に留まり、ブロックされread(2)
ます。その間、リモート側でシェルプロファイルが処理された後、scp
シンクモードで開始されread(2)
、データ転送の開始を示すバイナリゼロを待機します。
結論/ TLDR
一般的なステートメントのほとんどは、.bashrc
対話型シェルでのみ有用です。rsh
またはでリモートコマンドを実行するときは有用ではありませんssh
。ほとんどのこのような状況は、シェル変数、別名を設定し、所望されていない関数を定義するには-と印刷の任意のテキストを標準出力へののようなプログラムを使用してファイルを転送する場合は積極的に有害ですscp
かsftp
。現在のシェルが非対話型であることを確認した後に終了することが、の最も安全な動作です.bashrc
。