Dies ist eine Frage, die ich vor ein paar Wochen hier posten wollte. Wie bei Terdon habe ich verstanden, dass a .bashrc
nur für interaktive Bash-Shells bereitgestellt wird , sodass nicht .bashrc
überprüft werden muss, ob es in einer interaktiven Shell ausgeführt wird. Verwirrenderweise hatten alle von mir verwendeten Distributionen (Ubuntu, RHEL und Cygwin) eine Art Prüfung (Test $-
oder $PS1
), um sicherzustellen, dass die aktuelle Shell interaktiv ist. Ich mag keine Frachtkultprogrammierung, deshalb habe ich mich daran gemacht, den Zweck dieses Codes in meinem zu verstehen .bashrc
.
Bash hat einen speziellen Fall für Remote-Shells
Nachdem ich das Problem untersucht hatte, stellte ich fest, dass Remote-Shells unterschiedlich behandelt werden. Während nicht interaktive Bash-Shells normalerweise keine ~/.bashrc
Befehle beim Start ausführen, wird ein Sonderfall gemacht, wenn die Shell vom Remote-Shell-Daemon aufgerufen wird :
Bash versucht zu bestimmen, wann es mit seiner Standardeingabe ausgeführt wird, die mit einer Netzwerkverbindung verbunden ist, wie es normalerweise vom Remote-Shell-Dämon rshd
oder vom Secure-Shell-Dämon ausgeführt wird sshd
. Wenn Bash feststellt, dass es auf diese Weise ausgeführt wird, liest es Befehle von ~ / .bashrc und führt sie aus, sofern diese Datei vorhanden und lesbar ist. Es wird dies nicht tun, wenn es als aufgerufen wird sh
. Die --norc
Option kann verwendet werden , um dieses Verhalten zu hemmen, und die --rcfile
Option verwendet werden kann , eine andere Datei zu zwingen , zu lesen, aber weder rshd
noch im sshd
Allgemeinen die Schale mit diesen Optionen aufrufen oder es ihnen ermöglichen, festgelegt werden.
Beispiel
Fügen Sie am Anfang einer Fernbedienung Folgendes ein .bashrc
. (Wenn .bashrc
von .profile
oder bezogen .bash_profile
, deaktivieren Sie dies vorübergehend während des Tests):
echo bashrc
fun()
{
echo functions work
}
Führen Sie die folgenden Befehle lokal aus:
$ ssh remote_host 'echo $- $0'
bashrc
hBc bash
- No
i
in $-
gibt an, dass die Shell nicht interaktiv ist .
- Keine führenden
-
in $0
zeigt an, dass die Schale nicht um ein Login - Shell .
In der Fernbedienung definierte Shell-Funktionen .bashrc
können auch ausgeführt werden:
$ ssh remote_host fun
bashrc
functions work
Ich bemerkte , dass das ~/.bashrc
ist nur bezogen , wenn ein Befehl für als Argument angegeben wird ssh
. Dies ist sinnvoll: wenn ssh
zum Starten einer regulären Anmeldeshell verwendet .profile
oder .bash_profile
ausgeführt wird (und .bashrc
nur dann, wenn dies ausdrücklich durch eine dieser Dateien erfolgt).
Der Hauptvorteil, den ich .bashrc
beim Ausführen eines (nicht interaktiven) Remote-Befehls habe, ist, dass Shell-Funktionen ausgeführt werden können. Die meisten Befehle in einem Typical .bashrc
sind jedoch nur in einer interaktiven Shell relevant, z. B. werden Aliase nur dann erweitert, wenn die Shell interaktiv ist.
Remote-Dateiübertragungen können fehlschlagen
Dies ist normalerweise kein Problem , wenn rsh
oder ssh
verwendet , um ein interaktiv Login - Shell oder wenn nicht-interaktiver Shells zu beginnen , wird verwendet , um Befehle auszuführen. Aber es kann ein Problem sein für Programme wie rcp
, scp
und sftp
dass verwenden Remote - Schalen für die Datenübertragung.
Es stellt sich heraus, dass die Standard-Shell des Remote-Benutzers (wie Bash) implizit gestartet wird, wenn der scp
Befehl verwendet wird. Es gibt keine Erwähnung in der Manpage - nur eine Erwähnung, scp
die ssh
für die Datenübertragung verwendet wird. Dies hat zur Folge, dass die .bashrc
Dateiübertragung fehlschlägt ,
wenn der Befehl Befehle enthält, die an die Standardausgabe gesendet werden. Beispielsweise schlägt scp fehlerfrei fehl .
Siehe auch diesen verwandten Red Hat-Fehlerbericht von vor 15 Jahren, scp bricht ab, wenn es einen Echo-Befehl in / etc / bashrc gibt (der schließlich geschlossen wurde als WONTFIX
).
Warum scp
und sftp
scheitern
SCP (Secure Copy) und SFTP (Secure File Transfer Protocol) haben ihre eigenen Protokolle für die lokale und die entfernte Seite, um Informationen über die übertragenen Dateien auszutauschen. Unerwarteter Text vom entfernten Ende wird (falsch) als Teil des Protokolls interpretiert und die Übertragung schlägt fehl. Laut FAQ aus dem Schneckenbuch
Was oft geschieht, ist jedoch, dass es Aussagen entweder im System oder pro-Benutzer - Shell - Startdateien auf dem Server ( .bashrc
, .profile
,
/etc/csh.cshrc
, .login
usw.) , die Ausgabe von Textnachrichten auf Login, soll durch den Menschen gelesen werden (wie fortune
, echo "Hi there!"
, usw.).
Solcher Code sollte nur bei interaktiven Anmeldungen ausgegeben werden, wenn eine
tty
Standardeingabe angehängt ist. Wenn dieser Test nicht durchgeführt wird, werden diese Textnachrichten dort eingefügt, wo sie nicht hingehören. In diesem Fall wird der Protokolldatenstrom zwischen scp2
/ sftp
und verschmutzt sftp-server
.
Der Grund, warum die Shell-Startdateien überhaupt relevant sind, ist, dass sshd
die Shell des Benutzers verwendet wird, wenn Programme im Namen des Benutzers gestartet werden
(z. B. mit / bin / sh -c "Befehl"). Dies ist eine Unix-Tradition und hat Vorteile:
- Die üblichen Einstellungen des Benutzers (Befehls-Aliase, Umgebungsvariablen, umask usw.) werden wirksam, wenn Remote-Befehle ausgeführt werden.
- Die übliche Vorgehensweise, die Shell eines Kontos zum Deaktivieren auf / bin / false zu setzen, verhindert, dass der Besitzer Befehle ausführt, sollte die Authentifizierung aus irgendeinem Grund dennoch versehentlich erfolgreich sein.
Details zum SCP-Protokoll
Für diejenigen, die sich für die Details der Funktionsweise von SCP interessieren, fand ich interessante Informationen unter Funktionsweise des SCP-Protokolls , einschließlich Details zum Ausführen von scp mit gesprächigen Shell-Profilen auf der Remote-Seite. :
Dies kann beispielsweise passieren, wenn Sie Folgendes zu Ihrem Shell-Profil auf dem fernen System hinzufügen:
Echo ""
Warum hängt es nur? Das kommt von der Art und Weise , wie scp
in Quelle - Modus wartet auf die Bestätigung der ersten Protokollnachricht. Wenn es sich nicht um eine binäre 0 handelt, wird erwartet, dass es sich um eine Benachrichtigung über ein Remote-Problem handelt, und es wird darauf gewartet, dass weitere Zeichen eine Fehlermeldung bilden, bis die neue Zeile eintrifft. Da Sie nach der ersten Zeile keine weitere neue Zeile gedruckt haben, scp
bleibt Ihre lokale Zeile in einer Schleife und ist blockiert read(2)
. In der Zwischenzeit wurde nach der Verarbeitung des Shell-Profils auf der Remote-Seite der scp
Sink-Modus gestartet, der ebenfalls blockiert read(2)
und auf eine binäre Null wartet, die den Beginn der Datenübertragung angibt.
Fazit / TLDR
Die meisten Anweisungen in einem Typical .bashrc
sind nur für eine interaktive Shell nützlich - nicht, wenn Remotebefehle mit rsh
oder ausgeführt werden ssh
. In den meisten solchen Situationen Setzen von Shell - Variablen, Aliase und Funktionen definieren , nicht erwünscht ist - und Druck eines beliebigen Textes an der Standardausgabe ist aktiv schädlich , wenn Dateien mit Programmen wie die Übertragung scp
oder sftp
. Das Beenden nach der Überprüfung, ob die aktuelle Shell nicht interaktiv ist, ist das sicherste Verhalten für .bashrc
.