Warum erhält ein SSH-Remotebefehl weniger Umgebungsvariablen als bei manueller Ausführung? [geschlossen]

239

Ich habe einen Befehl, der einwandfrei ausgeführt wird, wenn ich ssh auf einem Computer ausführe und ihn ausführe, der jedoch fehlschlägt, wenn ich versuche, ihn mit einem Remote-ssh-Befehl wie dem folgenden auszuführen:

ssh user@IP <command>

Der Vergleich der Ausgabe von "env" mit beiden Methoden wird in verschiedenen Umgebungen erneut ausgeführt. Wenn ich mich manuell am Computer anmelde und env ausführe, erhalte ich viel mehr Umgebungsvariablen als beim Ausführen von:

ssh user@IP "env"

Irgendeine Idee warum?

Tom Feiner
quelle
30
Warum genau ist diese Frage als Off-Topic geschlossen?
Jottr
13
Wahrscheinlich, weil es nicht mit der Programmierung zusammenhängt. Es sollte auf Super User verschoben anstatt geschlossen worden sein.
Daniel H
8
bashist keine Skriptsprache?
Dan Nissenbaum
In Debian 8 musste ich aus irgendeinem Grund die Shell ändern, um in / etc / passwd zu schlagen. Selbst eine Neukonfiguration des Strichs, um / bin / sh auf Bash zeigen zu lassen, half nichts.
user1050755

Antworten:

173

Es gibt verschiedene Arten von Muscheln. Die SSH-Befehlsausführungsshell ist eine nicht interaktive Shell, während Ihre normale Shell entweder eine Anmeldeshell oder eine interaktive Shell ist. Beschreibung folgt aus Man Bash:

       Eine Login-Shell ist eine, deren erstes Argumentationszeichen
       Null ist ein - oder eins, das mit der Option --login gestartet wurde.

       Eine interaktive Shell wird ohne Nichtoption gestartet
       Argumente und ohne die Option -c, deren Standardeingabe
       und Fehler sind beide mit Klemmen verbunden (wie bestimmt)
       durch isatty (3)) oder man begann mit der Option -i. PS1 ist
       set und $ - enthält i, wenn bash interaktiv ist, was a erlaubt
       Shell-Skript oder eine Startdatei, um diesen Status zu testen.

       Die folgenden Absätze beschreiben, wie bash seine ausführt
       Startdateien. Wenn eine der Dateien vorhanden ist, aber nicht vorhanden sein kann
       Lesen, Bash meldet einen Fehler. Tildes werden in einer Datei erweitert
       Namen wie unten unter Tilde Expansion in der
       ERWEITERUNGSBEREICH.

       Wenn bash als interaktive Login-Shell oder als aufgerufen wird
       eine nicht interaktive Shell mit der Option --login, es zuerst
       liest und führt Befehle aus der Datei / etc / profile aus, wenn
       Diese Datei existiert. Nach dem Lesen dieser Datei sucht es nach
       ~ / .bash_profile, ~ / .bash_login und ~ / .profile
       bestellen und liest und führt Befehle vom ersten aus
       das existiert und ist lesbar. Die Option --noprofile kann
       Wird verwendet, wenn die Shell gestartet wird, um dieses Verhalten zu verhindern
       ior.

       Wenn eine Anmeldeshell beendet wird, liest bash Befehle und führt sie aus
       aus der Datei ~ / .bash_logout, falls vorhanden.

       Bei einer interaktiven Shell handelt es sich nicht um eine Login-Shell
       gestartet, Bash liest und führt Befehle von ~ / .bashrc aus,
       wenn diese Datei existiert. Dies kann durch Verwendung der
       --norc Option. Die Option --rcfile file erzwingt Bash
       Befehle aus der Datei lesen und ausführen statt
       ~ / .bashrc.

       Wenn bash nicht interaktiv gestartet wird, wird eine Shell ausgeführt
       Skript sucht beispielsweise nach der Variablen BASH_ENV in
       die Umgebung, erweitert ihren Wert, wenn es dort erscheint,
       und verwendet den erweiterten Wert als Namen einer zu lesenden Datei
       und ausführen. Bash verhält sich wie der folgende Befehl
       wurden ausgeführt:
              if [-n "$ BASH_ENV"]; dann . "$ BASH_ENV"; fi
       Der Wert der Variablen PATH wird jedoch nicht zur Suche verwendet
       für den Dateinamen.

Vinko Vrsalovic
quelle
7
Tolle Antwort, dies war genau das Problem. Die benötigten Umgebungsvariablen befanden sich in / etc / bashrc, das nicht im nicht interaktiven Modus bezogen wird. Das Verschieben nach / etc / profile hat das Problem behoben. Vielen Dank!
Tom Feiner
1
Diese Antwort ist nur eine Teillösung. Weitere Informationen: Fügen Sie den verschiedenen Dateien, die bezogen werden, eine andere Umgebungsvariable hinzu (z. B. SOURCED_SYSTEM_ETC_BASHRC exportieren): / etc / profile, etc / bashrc, ~ / .profile, ~ / .bash_profile, ~ / bashrc. Suchen Sie dann in der Jenkins-Ausgabe nach dieser eindeutigen Variablen. In meinem Fall habe ich / etc / bashrc so aktualisiert, dass es 'export SOURCED_SYSTEM_ETC_BASHRC = yes' enthält, und diese Variable wurde im Jenkins-Protokoll für den Knoten angezeigt. In meinem Fall müssen Umgebungsvariablen für Jenkins-Slaves in / etc / bashrc abgelegt werden. Jenkins ssh Login nur bezogen / etc / bashrc.
Coder Roadie
Korrektur: Ich meinte /etc/bash.bashrc, nicht / etc / bashrc.
Coder Roadie
37
Das ist eine ziemliche Textwand. Ich denke, es wäre hervorzuheben, ssh user@host "bash --login -c 'command arg1 ...'"dass die Remote-Shell die Anmeldeumgebung einrichtet. Der Abschnitt, den Sie zitiert haben, erwähnt zwar, --loginaber es wäre leicht, dies zu übersehen.
Codebart
Vielen Dank für diesen Beitrag. Früher habe ich ssh <ssh options> <IP> bash --login my_script.shein Skript auf dem Remotecomputer ausgeführt, eine JAVA_HOME
Belohnung ausgeführt
117

Wie wäre es mit der Beschaffung des Profils, bevor Sie den Befehl ausführen?

ssh user@host "source /etc/profile; /path/script.sh"

Vielleicht haben Sie es am besten zu ändern finden , dass zu ~/.bash_profile, ~/.bashrcoder was auch immer.

(Wie hier (linuxquestions.org) )

Ian Vaughan
quelle
1
Hatte dieses Problem, funktionierte diese Lösung großartig.
Sam152
10
Es ist lächerlich, immer zusätzlichen Code eingeben zu müssen, um die Umgebung zu beschaffen!
Michael
4
Man tippt diese Art von Dingen selten wiederholt, normalerweise befindet es sich in einem Skript, und als solches spielt es keine Rolle, wie viel "zusätzlicher Code" vorhanden ist, solange es funktioniert: tm:
Ian Vaughan
1
Wenn ich sowohl / etc / profile als auch ~ / .bash_profile als Quelle verwende (um Benutzerzusätze zum Pfad zu erhalten), funktioniert es, aber es ist hässlich. Es muss eine einfachere Möglichkeit geben, den Befehl (in meinem Fall xterm) anzuweisen, die "interaktive" Anmeldung zu verwenden und den vollständigen benutzerspezifischen Pfad auf dem Remotecomputer zu erhalten.
Jess
ssh $ 1 "source ~ / .bashrc; ~ / temp_unix.sh" Hier hat temp_unix.sh den Export MANI_HOME = "mani deepak", aber es funktioniert nicht.
Mani Deepak
90

Die Shell-Umgebung wird beim Ausführen des Remote-Befehls ssh nicht geladen. Sie können die SSH-Umgebungsdatei bearbeiten:

vi ~/.ssh/environment

Sein Format ist:

VAR1=VALUE1
VAR2=VALUE2

Überprüfen Sie auch die sshdKonfiguration auf PermitUserEnvironment=yesOption.

dpedro
quelle
1
Perfektion! +100 wenn ich könnte :)
Dexter
VisualGDB schlug mit dem Fehler "bash: gcc: Befehl nicht gefunden" fehl und diese Lösung korrigierte dies.
KalenGi
Fantastisch. Ich wünschte, ich hätte es vor Jahren gewusst.
Gravitation
Das ist die perfekte Antwort!
Jirapong
1
@ pg2455 Obwohl Sie nicht immer in der Lage sind, sshd auf Ihrem Server zu konfigurieren (oder es nicht für alle aktivieren möchten), können Sie Ihre Benutzerumgebung dennoch bearbeiten
dpedro
63

Ich hatte ein ähnliches Problem, aber am Ende fand ich heraus, dass ~ / .bashrc alles war, was ich brauchte.

In Ubuntu musste ich jedoch die Zeile kommentieren, die die Verarbeitung von ~ / .bashrc beendet:

#If not running interactively, don't do anything
[ -z "$PS1" ] && return
tomaszbak
quelle
8
Alternativ können Sie einfach Ihren gesamten "nicht interaktiven" Code über diese Zeile setzen.
Machineghost
schön, hat mir viel Zeit gespart :) danke
Lance Pollard
Vielen Dank. Fügen Sie einfach hinzu, dass die Datei mit der return-Anweisung unter zu finden ist /etc/bash.bashrc.
Adarshr
Gibt es überhaupt eine Möglichkeit, diesen Code auf dem Server zu umgehen, ohne ihn zu ändern?
Yoni
Ich habe so viel Zeit damit verbracht zu verstehen, warum mein Skript nicht funktioniert hat. Wer hielt es für eine gute Idee, diese Zeilen in die .bashrc zu setzen ???
Sharcoux
4

Ich fand eine einfache Lösung für dieses Problem darin, Quelle / etc / profile oben in der Datei script.sh hinzuzufügen, die ich auf dem Zielsystem ausführen wollte. Auf den Systemen hier wurden die Umgebungsvariablen, die von script.sh benötigt wurden, so konfiguriert, als würden sie von einer Anmeldeshell ausgeführt.

In einer der vorherigen Antworten wurde vorgeschlagen, ~ / .bashr_profile etc ... zu verwenden. Ich habe nicht viel Zeit damit verbracht, aber das Problem dabei ist, wenn Sie einem anderen Benutzer auf dem Zielsystem als der Shell auf dem Quellsystem, von dem aus Sie sich anmelden, einen SSH senden. Es scheint mir, dass dies den Benutzer des Quellsystems verursacht Name, der für das ~ verwendet werden soll.

Futter
quelle
Perfekt! Schöne einzeilige Lösung für das Problem.
Corpico
3

Exportieren Sie einfach die gewünschten Umgebungsvariablen über die Prüfung für eine nicht interaktive Shell in ~ / .bashrc.

Michael MacDonald
quelle