`ssh <host>`ist eine Login-Shell, aber` ssh <host> <command></command>ist nicht? </host></host>

2716
Ryan Lue

Ich habe festgestellt, dass ich, wenn ich einen Befehl direkt auf einem SSH-Host mit der ssh <host> <command>Syntax ausführte, .bashrcdie Ausgabe von .bash_profile(oder .profile) aber nicht die Ausgabe von (oder ) sehe .

Wenn ich zum Beispiel den folgenden Befehl oben in beiden Dateien platziere,

echo $ 

und manuell Quelle .bash_profile(welche Quellen .bashrcwiederum), werde ich sehen

$ . .bash_profile .bash_profile .bashrc 

Dies ist die gleiche Ausgabe, die ich sehe, wenn ich mich remote über SSH mit ssh <host>diesem Befehl an diesem Computer anmelde . (Und wenn ich mich .bash_profilevorübergehend an einem anderen Ort befinde, wird keine dieser Zeilen wiederholt.)

Wenn ich jedoch einen Befehl direkt auf der Remote-Maschine mit der ssh <host> <command>Form von ausführe ssh, sieht die Ausgabe folgendermaßen aus:

$ ssh <host> echo foo /home/rlue/.bashrc foo 

Ich verstehe, dass der Unterschied zwischen .bash_profileund .bashrcist, dass ersteres für Login-Shells ist, während letzteres für interaktive, nicht-Login-Shells ist .

Ich habe folgendes geschlossen:

  1. ssh <host>Quellen nur .bash_profilewährend
  2. ssh <host> <command>nur Quellen .bashrc, was bedeutet
  3. Ersteres ist eine Login-Shell und letzteres nicht.

Sind diese Schlussfolgerungen richtig? Warum wird ssh <host> <command>sie als interaktive Shell ohne Anmeldung behandelt? Meldet sich SSH nicht immer noch beim Remote-Computer an, um den Befehl auszuführen?

10
Ausgabe von ".bashrc"? Diese Datei soll keine Ausgabe erzeugen. Jede Ausgabe von `.bashrc` kann alle Werkzeuge mit ssh als Transportmittel beschädigen. kasperd vor 6 Jahren 0
Meinetwegen. In diesem Fall haben ein paar Zeilen in `.bashrc` einen Fehler ausgegeben, ähnliche Zeilen in` .bash_profile` jedoch nicht. Ich nutzte die Gelegenheit, um die Diskrepanz zu untersuchen, bevor die fehlerhaften Linien korrigiert wurden. Ryan Lue vor 6 Jahren 0

3 Antworten auf die Frage

11
Eric Renouf

OpenSSH (am wahrscheinlichsten, was Sie ausführen) entscheidet, ob Sie eine Login-Shell erstellen möchten oder nicht. Dies geschieht nur, wenn Sie keinen bestimmten Befehl ausführen. Von man ssh:

 If command is specified, it is executed on the remote host instead of a login shell. 

Es ist also eine Implementierungsentscheidung für den SSH-Server, ob er eine Login-Shell erstellen möchte oder nicht, und wenn Sie einen Befehl zur Ausführung geben, ist dies nicht der Fall.

Während sshein Login ausgeführt wird, wenn Sie einen Befehl ausführen und beenden, ist es dem Erstellen einer Shell viel ähnlicher, nur um diesen Befehl auszuführen, als wenn Sie eine Login-Umgebung erhalten. Es scheint, dass die Leute, die OpenSSH schreiben, beschlossen haben, es als eine solche Aufgabe zu behandeln.

Sie erstellen eine nicht interaktive, nicht angemeldete Shell, um den Befehl auszuführen, da dies der Sinn ist, einen Befehl in einem anderen Kontext / in einer anderen Shell auszuführen. Normalerweise würden nicht interaktive Shells nicht automatisch beschafft, ~/.bashrcwas hier eindeutig geschieht. bashversucht eigentlich, uns hier draußen zu helfen. Aus den Unterlagen

Wird vom Remote-Shell-Daemon aufgerufen

Bash versucht zu ermitteln, wann es ausgeführt wird, wobei seine Standardeingabe an eine Netzwerkverbindung angeschlossen ist, wie dies vom Remote-Shell-Daemon (normalerweise rshd oder dem sicheren Shell-Daemon sshd) ausgeführt wird. Wenn Bash feststellt, dass es auf diese Weise ausgeführt wird, liest und führt es Befehle aus ~ / .bashrc aus, sofern diese Datei existiert und lesbar ist. Es wird dies nicht tun, wenn es als sh aufgerufen wird. Die Option --norc kann verwendet werden, um dieses Verhalten zu verhindern, und die Option --rcfile kann verwendet werden, um das Lesen einer anderen Datei zu erzwingen. Weder rshd noch sshd rufen jedoch normalerweise die Shell mit diesen Optionen auf oder erlauben die Angabe.

"... es wird auf dem Remote-Host statt einer Login-Shell ausgeführt." Ich verstehe diese Dichotomie nicht. Wird der Befehl ** auf dem Remote-Host ** anstelle von ** in einer Login-Shell ** ausgeführt, oder ** wird der Befehl ** auf dem Remote-Host ausgeführt, anstatt ** eine Login-Shell **, die dort ausgeführt wird ? Wenn der erstere, wie ist es dann oder? (ist es normalerweise nicht beide?) Wenn letzteres noch im Kontext der _some_-Shell ausgeführt wird, nicht wahr? (eine interaktive, keine Anmeldung?) Meine Frage bezieht sich auch auf die Semantik - was bedeutet "Login-Shell" und warum sollte OpenSSH nicht für einzelne Befehle erstellt werden? Ryan Lue vor 6 Jahren 0
@RyanLue Die verschiedenen "Flavours" von Shells machen jeweils bestimmte Aufgaben einfacher / sicherer / optimierter usw. Während ein `ssh 'ein Login erfordert, haben die Implementierer anscheinend entschieden, dass es unter bestimmten Umständen erforderlich ist, z. B. die Ausführung eines Befehls und return, brauchen Sie nicht von den zusätzlichen Schritten zu profitieren, die eine Login-Shell ausführt, und überspringen diese. In der Tat gibt es eine Shell, die ausgeführt wird. Ich nehme an, dass sie hauptsächlich die Umgebung einrichten soll. Da die Shell nicht für den angemeldeten Benutzer bereitgestellt wird, behandeln sie ihn so, als hätte der Benutzer gerade eine neue Shell gestartet, um diese auszuführen Befehl Eric Renouf vor 6 Jahren 0
"Also gibt es tatsächlich eine Shell, die ausgeführt wird. Ich nehme an, dass sie hauptsächlich die Umgebung einrichten soll ..." <aber ich habe gerade damit experimentiert, und es scheint, dass `ssh `erbt nicht die Umgebung einer vorhandenen Login-Shell. Zum Beispiel `$ ssh \ $ PATH` gibt den Pfad so zurück, als wäre er _without_sourcing `.bash_profile` (oder sozusagen` .profile ') ... Warum sollten Sie diesen Schritt aus praktischen Gründen umgehen? Ryan Lue vor 6 Jahren 0
“... die Implementierer entschieden anscheinend, dass sie unter bestimmten Umständen, z. B. die Aufforderung, einen Befehl auszuführen und zurückzukehren, die zusätzlichen Schritte, die eine Login-Shell ausführt, nicht benötigen / nutzen und dies auch überspringen. < nach Klarstellung / Einsicht in diese Designauswahl suchen. Ich definiere meinen `PATH` in` .profile` - ist es nicht genau das, was Sie möchten, bevor Sie einen beliebigen Befehl auf einem Remote-Host ausführen? Ryan Lue vor 6 Jahren 0
@RyanLue Ich habe gerade meine Antwort geändert, um einen Versuch zu unternehmen, warum ich denke, dass sie diese Wahl getroffen haben Eric Renouf vor 6 Jahren 0
Vielen Dank! Re: "Sie erstellen eine nicht interaktive, nicht angemeldete Shell, um den Befehl auszuführen." Wenn dies zutrifft, warum wird dann `.bashrc` beschafft? ([`.bashrc` wird auf interaktiven Shells ohne Login ausgeführt] (https://stackoverflow.com/a/415444/4865822) für den Datensatz.) Ryan Lue vor 6 Jahren 0
@RyanLue ist ein guter Fang, und die Antwort wurde nun so aktualisiert, dass sie auch dies beinhaltet Eric Renouf vor 6 Jahren 0
Beeindruckend. Sie sind wirklich die Extrameile gegangen; Ich wünschte, ich hätte mehr als einen positiven Beitrag zu geben. Wenn Sie Lust haben, einige Punkte auf der Unix SE zu gewinnen, hat [diese Frage dort cross-gepostet] (https://unix.stackexchange.com/questions/374780/why-does-openssh-treat-ssh-host-command- as-a-non-login-shell). (Denken Sie, dass dies Auswirkungen darauf hat, welche Einstellungen in ".bash_profile" und in ".bashrc" gehören?) Ich verwende beispielsweise ".bashrc", um sicherzustellen, dass das Terminal in einer tmux-Sitzung geöffnet wird `tmux new -A`, aber ich würde es natürlich vorziehen, dies nicht auf einer nicht interaktiven ssh-Shell zu beziehen ...) Ryan Lue vor 6 Jahren 0
@RyanLue SE rät eigentlich davon ab, Cross-Postings zu löschen, daher würde ich empfehlen, entweder das eine oder das andere zu löschen, und ich denke, das Problem, das Sie haben, ist, warum viele bashrc Tests haben, um zu sehen, ob sie interaktiv sind oder nicht Eric Renouf vor 6 Jahren 0
@RyanLue Der Boks SSH-Server unterscheidet verschiedene Verwendungsmöglichkeiten von SSH und kann Berechtigungen für jede vergeben. Fernanmeldung, Fernausführung, Fernkopie. Vielleicht hilft Ihnen das zu verstehen, warum Sie das von Ihnen beschriebene Verhalten haben könnten. Remote Login (interaktive Nutzung) ist in einer Hochsicherheitsumgebung möglicherweise zu viel verlangt. Openssh kann durch Verwendung von rbash / rksh und 'logout' in .bash_profile oder chroot eingeschränkt werden. bbaassssiiee vor 6 Jahren 1
3
zwol

The why of this behavior lies at a lower level than shells: ssh host (the "login shell" case) uses a pseudoterminal on the remote host, to communicate between the sshd server process and the shell; ssh host command uses pipes between sshd and command, instead. Pseudoterminals are necessary to make interactive use of a command interpreter, such as a shell, or the "read-eval-print" mode of a scripting language; they implement a bunch of human-friendly features like being able to backspace over typos. But they have more overhead and (depending on configuration) do not allow arbitrary data to pass through unmodified, so SSH avoids using them when interaction is not going to be happening.

Sometimes SSH's command/no command heuristic gets this wrong; it can be overridden with the -t and -T switches. For instance, to log into a remote machine and immediately reattach a suspended screen session, you need to do ssh -t host screen -R; ssh host screen -R will cause screen to complain about not being connected to a terminal. I can't think of a situation when you would actually want to use -T, but it's there if you ever do find one.

1
Genaro Morales

Zuerst müssen Sie die verschiedenen Typen sehen, Sie können dies lesen:

https://unix.stackexchange.com/questions/170493/login-non-login-und-interactive-non-interactive-shells

Wenn Sie jetzt Ihre Bashrc öffnen, werden Sie am Anfang Folgendes sehen:

# If not running interactively, don't do anything [ -z "$PS1" ] && return 

Das heißt, je nachdem, wie Sie auf das System zugreifen, lädt diese Datei den Code hinein oder nicht.

Okay, aber dies wirft eine interessante Frage auf: `.bashrc` kann so geschrieben werden, dass sie nicht aufgerufen wird, wenn sie in einem nicht interaktiven Kontext aufgerufen wird (_i.e., _, Wenn es keine„ Prompt-Anweisung “/` $ PS1 gibt.) `variable). Aber `ssh `** ist entschieden nicht interaktiv **; Das heißt, _nicht_ gibt eine Eingabeaufforderung aus. Warum sollte OpenSSH so gestaltet sein, dass eine interaktive Eingabeaufforderung ohne Anmeldung (eine, die versucht, `.bashrc 'zu finden) für diesen scheinbar nicht interaktiven Anwendungsfall erstellt wird? Ryan Lue vor 6 Jahren 0