Dies ist eine Frage, die ich vor ein paar Wochen hier posten wollte. Wie bei Terdon habe ich verstanden, dass a .bashrcnur 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 ~/.bashrcBefehle 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 rshdoder 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 --norcOption kann verwendet werden , um dieses Verhalten zu hemmen, und die --rcfileOption verwendet werden kann , eine andere Datei zu zwingen , zu lesen, aber weder rshdnoch im sshdAllgemeinen 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 .bashrcvon .profileoder 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
iin $-gibt an, dass die Shell nicht interaktiv ist .
- Keine führenden
-in $0zeigt an, dass die Schale nicht um ein Login - Shell .
In der Fernbedienung definierte Shell-Funktionen .bashrckönnen auch ausgeführt werden:
$ ssh remote_host fun
bashrc
functions work
Ich bemerkte , dass das ~/.bashrcist nur bezogen , wenn ein Befehl für als Argument angegeben wird ssh. Dies ist sinnvoll: wenn sshzum Starten einer regulären Anmeldeshell verwendet .profileoder .bash_profileausgeführt wird (und .bashrcnur dann, wenn dies ausdrücklich durch eine dieser Dateien erfolgt).
Der Hauptvorteil, den ich .bashrcbeim Ausführen eines (nicht interaktiven) Remote-Befehls habe, ist, dass Shell-Funktionen ausgeführt werden können. Die meisten Befehle in einem Typical .bashrcsind 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 rshoder sshverwendet , 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, scpund sftpdass 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 scpBefehl verwendet wird. Es gibt keine Erwähnung in der Manpage - nur eine Erwähnung, scpdie sshfür die Datenübertragung verwendet wird. Dies hat zur Folge, dass die .bashrcDateiü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 scpund sftpscheitern
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, .loginusw.) , 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
ttyStandardeingabe 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/ sftpund 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 scpin 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, scpbleibt 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 scpSink-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 .bashrcsind nur für eine interaktive Shell nützlich - nicht, wenn Remotebefehle mit rshoder 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 scpoder sftp. Das Beenden nach der Überprüfung, ob die aktuelle Shell nicht interaktiv ist, ist das sicherste Verhalten für .bashrc.