`ssh <host>` est un shell de connexion, mais `ssh <host> <command>` ne l'est pas?

12

J'ai remarqué que lorsque j'exécute une commande directement sur un hôte SSH en utilisant la ssh <host> <command>syntaxe, je vois la sortie de .bashrcmais pas la sortie de .bash_profile(ou .profile).

Par exemple, si je place la commande suivante en haut des deux fichiers,

echo ${BASH_SOURCE[0]}

et source manuellement .bash_profile(quelles sources .bashrcà leur tour), je vais voir

$ . .bash_profile
.bash_profile
.bashrc

C'est la même sortie que je vois si je me connecte à cet ordinateur à distance via SSH, en utilisant le ssh <host>formulaire de la commande. (Et si je range .bash_profiletemporairement ailleurs, aucune de ces lignes ne se répercute.)

Cependant, si j'exécute une commande directement sur la machine distante sous la ssh <host> <command>forme de ssh, la sortie ressemble à ceci:

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

Ma compréhension est que la différence entre .bash_profileet .bashrcest que le premier est pour les shells de connexion tandis que le second est pour les shells interactifs sans connexion .

J'ai conclu ce qui suit:

  1. ssh <host>sources uniquement .bash_profile,
  2. ssh <host> <command>sources uniquement .bashrc, ce qui signifie
  3. le premier est un shell de connexion et le second ne l'est pas.

Ces conclusions sont-elles correctes? Pourquoi est-il ssh <host> <command>traité comme un shell interactif sans connexion? SSH ne se connecte-t-il toujours pas à la machine distante pour exécuter la commande?

Ryan Lue
la source
sortie de .bashrc? Ce fichier n'est pas censé produire de sortie. Toute sortie de .bashrcpeut casser tous les outils en utilisant ssh comme transport.
kasperd
C'est suffisant. Dans ce cas, quelques lignes en .bashrclançaient une erreur, tandis que des lignes similaires .bash_profilene l'étaient pas. J'en ai profité pour enquêter sur l'écart avant de corriger les lignes incriminées.
Ryan Lue

Réponses:

12

OpenSSH (probablement ce que vous exécutez) décide de créer ou non un shell de connexion, et il ne le fait que si vous n'exécutez pas une commande spécifique. De man ssh:

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

C'est donc un choix d'implémentation pour le serveur ssh, qu'il veuille ou non créer un shell de connexion, et si vous donnez une commande à exécuter, ce n'est pas le cas.

Bien sshqu'il effectue une connexion, si vous lui faites exécuter une commande et quittez, cela ressemble beaucoup plus à la création d'un shell juste pour exécuter cette commande qu'à l'obtention d'un environnement de connexion. Il semble, étant donné que, que les gens qui écrivent OpenSSH ont décidé de le traiter comme ce genre de tâche.

Ils créent un shell non interactif et sans connexion pour exécuter la commande, car c'est l'esprit d'exécuter une commande dans un autre contexte / shell. Normalement, cependant, les shells non interactifs ne seraient pas automatiquement source, ~/.bashrcce qui se produit clairement ici. bashessaie en fait de nous aider ici. À partir des documents

Appelé par le démon shell distant

Bash tente de déterminer quand il est exécuté avec son entrée standard connectée à une connexion réseau, comme lorsqu'il est exécuté par le démon shell distant, généralement rshd, ou le démon shell sécurisé sshd. Si Bash détermine qu'il est exécuté de cette manière, il lit et exécute les commandes à partir de ~ / .bashrc, si ce fichier existe et est lisible. Il ne le fera pas s'il est invoqué en tant que sh. L'option --norc peut être utilisée pour inhiber ce comportement, et l'option --rcfile peut être utilisée pour forcer la lecture d'un autre fichier, mais ni rshd ni sshd n'appellent généralement le shell avec ces options ou ne permettent de les spécifier.

Eric Renouf
la source
"... il est exécuté sur l'hôte distant au lieu d'un shell de connexion." Je ne comprends pas cette dichotomie. La commande est-elle exécutée sur l'hôte distant au lieu d' un shell de connexion , ou la commande est-elle exécutée sur l'hôte distant, au lieu d' un shell de connexion qui y est exécuté? Si le premier, comment est-ce soit / ou? (n'est-ce pas normalement les deux? ) Si ce dernier est toujours exécuté dans le contexte d' un shell, n'est-ce pas? (interactif, sans connexion?) Donc ma question concerne également la sémantique - que signifie "login shell" et pourquoi OpenSSH serait-il conçu pour ne pas en créer une pour des commandes uniques?
Ryan Lue
@RyanLue Les différentes « saveurs » de coquilles chacune faciliter certaines tâches / plus sûr / optimisé , etc. Tout en faisant un sshnécessite une connexion, les exécutants ont apparemment décidé que , dans certaines circonstances, par exemple, en lui demandant d'exécuter une commande et retour, font pas besoin / bénéficier des étapes supplémentaires qu'un shell de connexion prend, et donc ils sautent cela. Donc, en effet, il y a un shell qui est exécuté, je suppose principalement pour configurer l'environnement, et puisque le shell ne sera pas fourni à l'utilisateur qui s'est connecté, ils le traitent comme si l'utilisateur venait de démarrer un nouveau shell pour exécuter ce commande
Eric Renouf
"Donc, en effet, il y a un shell qui s'exécute, je suppose surtout pour configurer l'environnement ..." <mais je viens de l'expérimenter, et il semble qu'il ssh <host> <command>n'hérite de l'environnement d'aucun shell de connexion existant. Par exemple, $ ssh <host> \$PATHrenvoie le chemin tel qu'il serait sans sourcing .bash_profile(ou .profile, pour ainsi dire) ... Dans un sens pratique, pourquoi voudriez-vous contourner cette étape?
Ryan Lue
"... les implémenteurs ont apparemment décidé que, dans certaines circonstances, par exemple en lui demandant d'exécuter une commande et de revenir, ils n'ont pas besoin / ne bénéficient pas des étapes supplémentaires qu'un shell de connexion prend, et donc ils sautent cela." <également, en recherchant spécifiquement des éclaircissements / idées sur ce choix de conception. Je définis mon PATHen .profile- est -ce pas exactement le genre de chose que vous voudriez chargé avant d' exécuter une commande arbitraire sur un hôte distant?
Ryan Lue
1
@RyanLue, le serveur ssh de Boks distingue les différentes utilisations de ssh et peut accorder des autorisations pour chacune. Connexion à distance, exécution à distance, copie à distance, peut-être que cela aide à comprendre pourquoi vous auriez le comportement que vous décrivez. La connexion à distance (utilisation interactive) peut être trop demander dans un environnement de haute sécurité. Openssh peut être restreint en utilisant rbash / rksh et 'logout' dans .bash_profile ou chroot.
bbaassssiiee
4

Le pourquoi de ce comportement se situe à un niveau inférieur à celui des shells: ssh host(le cas "login shell") utilise un pseudoterminal sur l'hôte distant, pour communiquer entre le sshdprocessus serveur et le shell; ssh host commandutilise des tuyaux entre sshdet command, à la place. Les pseudoterminaux sont nécessaires pour faire un usage interactif d'un interpréteur de commandes, comme un shell, ou le mode " read-eval-print " d'un langage de script; ils implémentent un tas de fonctionnalités conviviales comme la possibilité de revenir en arrière sur les fautes de frappe. Mais ils ont plus de surcharge et (selon la configuration) ne permettent pas à des données arbitraires de passer sans modification, donc SSH évite de les utiliser lorsque l'interaction ne se produira pas.

Parfois, l'heuristique de commande / pas de commande de SSH se trompe; il peut être remplacé par les commutateurs -tet -T. Par exemple, pour vous connecter à une machine distante et rattacher immédiatement une screensession suspendue , vous devez le faire ssh -t host screen -R; ssh host screen -Rentraînera screenà se plaindre de ne pas être connecté à un terminal. Je ne peux pas penser à une situation où vous vraiment envie d'utiliser -T, mais il est là si jamais vous ne trouvez un.

zwol
la source
1

Vous devez d'abord voir les différents types, vous pouvez lire ceci:

/unix/170493/login-non-login-and-interactive-non-interactive-shells

Maintenant, si vous ouvrez votre bashrc, vous verrez au début ceci:

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

Cela signifie que selon la façon dont vous accédez au système, ce fichier charge le code à l'intérieur ou non.

Genaro Morales
la source
D'accord, mais cela soulève une question intéressante: .bashrcpeut être écrit de manière à ne pas provenir s'il est appelé dans un contexte non interactif ( c'est-à-dire s'il n'y a pas de «déclaration rapide» / $PS1variable). Mais ssh <host> <command> est décidément non interactif ; c'est-à-dire qu'il ne déclenche pas d' invite de commandes. Alors, pourquoi OpenSSH serait-il conçu pour créer une invite interactive sans connexion (une qui essaie de se procurer .bashrc) pour ce cas d'utilisation apparemment sans connexion et non interactif ??
Ryan Lue