Warum unterscheiden sich Umgebungsvariablen mit `bash -c`?

12

Wie kommt es, dass folgendes, dh $PATHdirektes Echo von bash -c:

docker exec -i -t my_container bash -c "echo $PATH"

Gibt einen anderen Wert $PATHals den folgenden zurück, dh eine interaktive Bash-Sitzung wird gestartet und das $PATH?

docker exec -i -t my_container bash 
root@21e6d898c3c2:/# echo $PATH

Um dieser Frage einen Kontext zu geben, möchte ich einen Befehl im Container mit ausführen. docker execDieser Befehl befindet sich auf dem Pfad, wenn ich eine interaktive Bash-Sitzung starte, aber nicht, wenn ich nur den Befehl ausführe.

Die Verwendung des vollständigen Pfads der ausführbaren Datei ist in diesem Fall keine Problemumgehung, da der Befehl auf anderen Umgebungsvariablen basiert, die genau wie PATHin einer interaktiven Bash-Sitzung festgelegt wurden, jedoch nicht, wenn ich den Befehl direkt ausführe.

Alessandro Vernet
quelle
1
Zusätzlich zu dem, worauf @chicks hingewiesen hat, ersetzt die Verwendung von Ihren PATH, bevor Docker gestartet docker ... "echo $PATH"wird , geschweige denn die Bash-Shell. Wenn Sie möchten, dass der PATH der Shell unter Docker ausgeführt wird, verwenden Sie einfache Anführungszeichen ( ), um eine vorzeitige Auswertung der PATH-Variablen zu verhindern. docker ... 'echo $PATH'
Gordon Davisson

Antworten:

5

Wenn -cangegeben, bashwird nicht als interaktive oder Anmeldeshell ausgeführt , sodass nicht dieselben Startskripte gelesen werden. Alles, was in ,, oder gesetzt /etc/profileist ~/.bash_profile, ~/.bash_loginwird ~/.profiledefinitiv übersprungen.

Wie in der bashManpage erläutert :

Bash versucht festzustellen, wann es ausgeführt wird, wenn seine Standardeingabe mit einer Netzwerkverbindung verbunden ist, wie dies normalerweise vom Remote-Shell-Daemon rshdoder vom Secure-Shell-Daemon ausgeführt wird sshd. Wenn bash feststellt, dass es auf diese Weise ausgeführt wird, liest es Befehle von ~/.bashrc und ~/.bashrc, wenn diese Dateien vorhanden und lesbar sind.

Wenn Sie also nicht glauben, dass Sie eine Verbindung über das Netzwerk herstellen, wird die .bashrcDatei möglicherweise auch nicht gelesen, wodurch alles übersprungen wird, was im vorherigen Schritt nicht übersprungen wurde.

Lösung

Um dieses Problem zu umgehen, würde ich ein Skript erstellen, das das PATHauf etwas Passendes setzt, und dann den Befehl ausführen. Wenn Sie die vorhandenen .profileoder andere Dateien verwenden möchten, können Sie sie einfach in Ihrem Skript als Quelle verwenden .

Küken
quelle
4
warum nicht mit bash -l -c "Befehl"
ausführen
6

In Ihrem ersten Beispiel:

docker exec -i -t my_container bash -c "echo $PATH"

Dadurch wird die $PATHVariable mit Ihrer Shell auf Ihrem Docker-Client außerhalb des Containers ausgewertet und anschließend der erweiterte Wert als Befehl zum Ausführen innerhalb des Containers übergeben. Sie können den oben genannten Wert mit der Ausführung echo $PATHin der Befehlszeile außerhalb von Docker vergleichen und feststellen, dass sie identisch sind.

In Ihrem zweiten Beispiel:

docker exec -i -t my_container bash 
root@21e6d898c3c2:/# echo $PATH

Dadurch wird die $PATHVariable im Container ausgewertet .

Sie können Ihrem ersten Beispiel entkommen oder es in einfache Anführungszeichen setzen, um zu verhindern, dass die Bash-Shell auf Ihrer Workstation es erweitert, sodass es im Container ausgewertet wird. Beides würde funktionieren:

docker exec -i -t my_container bash -c "echo \$PATH"
docker exec -i -t my_container bash -c 'echo $PATH'
BMitch
quelle
1
Oder ... bash -c "printenv PATH"oder ... bash -c "declare -p PATH"die nur den Namen PATH (nicht seinen Wert) übergeben und das Programm oder die Shell im Container die Suche durchführen lassen
dave_thompson_085
2

Probieren Sie die -lOption für bash. Es wird in der Login-Shell ausgeführt und geladen /etc/profile.

docker exec -i -t my_container bash -lc "echo $PATH"
Max Ivak
quelle