Auf meiner Arch-Installation /etc/bash.bashrc
und /etc/skel/.bashrc
diese Zeilen enthalten:
# If not running interactively, don't do anything
[[ $- != *i* ]] && return
Unter Debian /etc/bash.bashrc
hat:
# If not running interactively, don't do anything
[ -z "$PS1" ] && return
Und /etc/skel/.bashrc
:
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac
Laut man bash
, jedoch lesen nicht interaktive Shells nicht einmal diese Dateien:
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.
Wenn ich das richtig verstehe, die *.bashrc
Dateien werden nur gelesen, wenn BASH_ENV
soll auf sie hinweisen. Dies kann nicht zufällig passieren und tritt nur auf, wenn jemand die Variable explizit entsprechend gesetzt hat.
Das scheint die Möglichkeit zu unterbrechen, dass Skripte die .bashrc
eines Benutzers beziehen automatisch durch Setzen von BASH_ENV
, etwas, das sich als nützlich erweisen könnte. Angesichts der Tatsache, dass bash diese Dateien niemals lesen wird, wenn es nicht interaktiv ausgeführt wird, es sei denn, es wird ausdrücklich dazu aufgefordert, warum sollte dann der Standardwert *bashrc
verwendet werden Dateien verbieten es?
Akzeptierte Antwort:
Diese Frage wollte ich hier vor ein paar Wochen stellen. Wie Terdon , ich habe verstanden, dass eine .bashrc
wird nur für interaktive Bash-Shells bereitgestellt, daher sollte .bashrc
nicht erforderlich sein um zu prüfen, ob es in einer interaktiven Shell läuft. Verwirrenderweise alle Die von mir verwendeten Distributionen (Ubuntu, RHEL und Cygwin) hatten eine Art Überprüfung (Testen von $-
oder $PS1
), um sicherzustellen, dass die aktuelle Shell interaktiv ist. Ich mag keine Cargo-Cult-Programmierung, also habe ich mich daran gemacht, den Zweck dieses Codes in meiner .bashrc
zu verstehen .
Bash hat einen Sonderfall für entfernte Shells
Nachdem ich das Problem untersucht hatte, entdeckte ich, dass Remote-Shells unterschiedlich behandelt werden. Während nicht interaktive Bash-Shells normalerweise ~/.bashrc
nicht ausführen Befehle beim Start, ein Sonderfall wird gemacht, wenn die Shell von einem entfernten Shell-Daemon aufgerufen wird:
Bash versucht festzustellen, wann es mit seiner Standardeingabe
verbunden mit einer Netzwerkverbindung ausgeführt wird, wie wenn es vom Remote-Shell-Daemon
ausgeführt wird, normalerweise rshd
, oder den Secure Shell-Daemon sshd
. Wenn Bash
feststellt, dass es auf diese Weise ausgeführt wird, liest und führt es Befehle
aus ~/.bashrc aus, wenn diese Datei existiert und lesbar ist. Dies wird nicht geschehen, wenn
als sh
aufgerufen wird . Der --norc
kann verwendet werden, um dieses Verhalten zu unterbinden,
und die --rcfile
Option kann verwendet werden, um das Lesen einer anderen Datei zu erzwingen, aber
weder rshd
noch sshd
generell die Shell mit diesen Optionen aufrufen oder
erlauben, dass sie angegeben werden.
Beispiel
Fügen Sie am Anfang einer entfernten .bashrc
Folgendes ein . (Falls .bashrc
wird von .profile
bezogen oder .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
- Kein
i
in$-
gibt an, dass die Shell nicht interaktiv ist . - Kein führender
-
in$0
gibt an, dass die Shell keine Anmelde-Shell ist .
Shell-Funktionen, die in der entfernten .bashrc
definiert sind kann auch ausgeführt werden:
$ ssh remote_host fun
bashrc
functions work
Mir ist aufgefallen, dass ~/.bashrc
ist nur sourced, wenn ein Befehl als Argument für ssh
angegeben wird . Das macht Sinn:wenn ssh
wird verwendet, um eine reguläre Login-Shell zu starten, .profile
oder .bash_profile
ausgeführt werden (und .bashrc
wird nur bezogen, wenn dies explizit durch eine dieser Dateien erfolgt).
Den Hauptvorteil sehe ich darin, .bashrc
zu haben Wenn Sie einen (nicht interaktiven) Remote-Befehl ausführen, können Shell-Funktionen ausgeführt werden. Die meisten Befehle sind jedoch in einer typischen .bashrc
sind nur in einer interaktiven Shell relevant, z. B. werden Aliase nicht erweitert, es sei denn, die Shell ist interaktiv.
Remote-Dateiübertragungen können fehlschlagen
Dies ist normalerweise kein Problem, wenn rsh
oder ssh
werden verwendet, um eine interaktive Anmelde-Shell zu starten oder wenn nicht interaktive Shells zum Ausführen von Befehlen verwendet werden. Es kann jedoch ein Problem sein für Programme wie rcp
, scp
und sftp
die Remote-Shells verwenden zum Übertragen von Daten.
Es stellt sich heraus, dass die Standard-Shell des Remote-Benutzers (wie Bash) implizit gestartet wird, wenn scp
verwendet wird Befehl. In der Manpage wird dies nicht erwähnt – nur eine Erwähnung, dass scp
verwendet ssh
für seine Datenübertragung. Das hat zur Folge, dass wenn die .bashrc
Befehle enthält, die auf die Standardausgabe gedruckt werden, schlägt die Dateiübertragung fehl , z. B. scp schlägt ohne Fehler fehl.
Warum scp
und sftp
scheitern
SCP (Secure Copy) und SFTP (Secure File Transfer Protocol) haben ihre eigenen Protokolle für das lokale und entfernte Ende, um Informationen über die zu übertragende(n) Datei(en) auszutauschen. Jeder unerwartete Text von der Gegenseite wird (fälschlicherweise) als Teil des Protokolls interpretiert und die Übertragung schlägt fehl. Laut einer FAQ aus dem Snail Book
Was jedoch häufig passiert, ist, dass Anweisungen entweder in den
System- oder in den Shell-Startdateien pro Benutzer auf dem Server (.bashrc
, .profile
, /etc/csh.cshrc
, .login
, etc.), die beim Login Textnachrichten ausgeben,
die von Menschen gelesen werden sollen (wie fortune
, echo "Hi there!"
usw.).
Dieser Code sollte nur bei interaktiven Anmeldungen eine Ausgabe erzeugen, wenn ein tty
vorhanden ist an die Standardeingabe angehängt. Wenn es diesen Test nicht durchführt, fügt es
diese Textnachrichten dort ein, wo sie nicht hingehören:in diesem Fall verunreinigt
der Protokollstrom zwischen scp2
/sftp
und sftp-server
.
Der Grund, warum die Shell-Startdateien überhaupt relevant sind, ist, dass sshd
verwendet die Shell des Benutzers, 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 (Befehlsaliase, Umgebungsvariablen, umask,
usw.) sind wirksam, wenn Remote-Befehle ausgeführt werden. - Die übliche Vorgehensweise, die Shell eines Kontos auf /bin/false zu setzen, um
sie zu deaktivieren, verhindert, dass der Besitzer Befehle ausführt, falls die Authentifizierung
aus irgendeinem Grund trotzdem erfolgreich ist.
SCP-Protokolldetails
Für diejenigen, die an den Details der Funktionsweise von SCP interessiert sind, habe ich interessante Informationen in How the SCP protocol works gefunden, die Details zu Running scp with talkative shell profiles on the remote side? enthalten :
Dies kann beispielsweise passieren, wenn Sie dies zu Ihrem Shell-Profil auf dem
Remote-System hinzufügen:
Echo „“
Warum hängt es nur? Das kommt von der Art wie scp
in Quelle mode
wartet auf die Bestätigung der ersten Protokollnachricht. Wenn es nicht binär
0 ist, erwartet es, dass es sich um eine Benachrichtigung über ein entferntes Problem handelt, und wartet auf
weitere Zeichen, um eine Fehlermeldung zu bilden, bis die neue Zeile eintrifft. Da
Sie nach der ersten keine weitere neue Zeile gedruckt haben, wird Ihr lokaler scp
nur
bleibt in einer Schleife, blockiert bei read(2)
. In der Zwischenzeit, nachdem das Shell
-Profil auf der entfernten Seite verarbeitet wurde, scp
im Sink-Modus gestartet,
was auch bei read(2)
blockiert , warten auf eine binäre Null, die den Beginn
der Datenübertragung anzeigt.
Fazit / TLDR
Die meisten Anweisungen in einer typischen .bashrc
sind nur für eine interaktive Shell nützlich – nicht, wenn Remote-Befehle mit rsh
ausgeführt werden oder ssh
. In den meisten solchen Situationen ist das Setzen von Shell-Variablen, Aliasnamen und das Definieren von Funktionen nicht erwünscht – und das Drucken irgendeines Textes to standard out ist aktiv schädlich, wenn Dateien mit Programmen wie scp
übertragen werden oder sftp
. Das Beenden nach dem Überprüfen, ob die aktuelle Shell nicht interaktiv ist, ist das sicherste Verhalten für .bashrc
.