C'est une question que j'allais poster ici il y a quelques semaines. Comme terdon , j'ai compris que a .bashrc
est uniquement destiné à des shells Bash interactifs; il ne devrait donc pas être nécessaire .bashrc
de vérifier s'il tourne dans un shell interactif. De manière confuse, toutes les distributions que j'utilise (Ubuntu, RHEL et Cygwin) avaient un type de vérification (testing $-
ou $PS1
) pour s'assurer que le shell actuel est interactif. Je n'aime pas la programmation culte de l'industrie du fret, alors je me suis efforcé de comprendre le but de ce code dans mon .bashrc
.
Bash a un cas particulier pour les obus distants
Après avoir étudié le problème, j'ai découvert que les coques distantes sont traitées différemment. Bien que les shells non interactifs Bash n'exécutent normalement pas de ~/.bashrc
commandes au démarrage, un cas particulier est créé lorsque le shell est appelé par le démon de shell distant :
Bash tente de déterminer quand il est exécuté avec son entrée standard connectée à une connexion réseau, comme si elle était exécutée par le démon de shell distant, généralement rshd
, ou par le démon de shell sécurisé sshd
. Si Bash détermine qu'il est exécuté de cette manière, il lit et exécute les commandes de ~ / .bashrc, si ce fichier existe et est lisible. Il ne le fera pas s'il est appelé sh
. L' --norc
option peut être utilisée pour empêcher ce comportement et l' --rcfile
option pour forcer la lecture d'un autre fichier, mais rshd
ni sshd
généralement ni invoquer le shell avec ces options ou permettre leur spécification.
Exemple
Insérez ce qui suit au début d’une télécommande .bashrc
. (Si .bashrc
provient de .profile
ou .bash_profile
, désactivez-le temporairement pendant les tests):
echo bashrc
fun()
{
echo functions work
}
Exécutez les commandes suivantes localement:
$ ssh remote_host 'echo $- $0'
bashrc
hBc bash
- No
i
in $-
indique que le shell n'est pas interactif .
- Non leader
-
en $0
indique que la coquille n'est pas une coquille de connexion .
Les fonctions shell définies dans la télécommande .bashrc
peuvent également être exécutées:
$ ssh remote_host fun
bashrc
functions work
J'ai remarqué que l' ~/.bashrc
on ne sourced lorsqu'une commande est spécifiée comme argument ssh
. Cela a du sens: quand ssh
est utilisé pour démarrer un shell de connexion normal, .profile
ou .bash_profile
est exécuté (et .bashrc
n’est recherché que si cela est fait explicitement par l’un de ces fichiers).
Le principal avantage que je peux constater .bashrc
lors de l’exécution d’une commande à distance (non interactive) est que les fonctions du shell peuvent être exécutées. Cependant, la plupart des commandes d'une commande typique .bashrc
ne sont pertinentes que dans un shell interactif. Par exemple, les alias ne sont pas développés sauf si le shell est interactif.
Les transferts de fichiers à distance peuvent échouer
Ce n'est généralement pas un problème lorsque rsh
ou ssh
sont utilisés pour démarrer un shell de connexion interactif ou lorsque des shells non interactifs sont utilisés pour exécuter des commandes. Cependant, cela peut être un problème pour des programmes tels que rcp
, scp
et sftp
qui utilisent des shells distants pour transférer des données.
Il s'avère que le shell par défaut de l'utilisateur distant (comme Bash) est lancé implicitement lors de l'utilisation de la scp
commande. Il n'y a aucune mention de cela dans la page de manuel - seulement une mention qui scp
utilise ssh
pour son transfert de données. Cela a pour conséquence que, si .bashrc
contient des commandes imprimant sur une sortie standard, les transferts de fichiers échoueront , par exemple,
scp échouera sans erreur .
Reportez-vous également à ce rapport de bogue Red Hat connexe datant d'il y a 15 ans: scp se brise lorsqu'il existe une commande echo dans / etc / bashrc (qui a finalement été fermée en tant que WONTFIX
).
Pourquoi scp
et sftp
échouer
SCP (copie sécurisée) et SFTP (protocole de transfert de fichier sécurisé) ont leurs propres protocoles pour les extrémités locale et distante afin d’échanger des informations sur le ou les fichiers en cours de transfert. Tout texte inattendu de l'extrémité distante est (à tort) interprété comme faisant partie du protocole et le transfert échoue. Selon une FAQ du livre d'escargot
Ce qui arrive souvent, cependant, est qu'il ya des déclarations contenues dans le système ou shell par l' utilisateur des fichiers de démarrage sur le serveur ( .bashrc
, .profile
,
/etc/csh.cshrc
, .login
, etc.) des messages texte de sortie sur connexion, destinés à être lus par les humains (comme fortune
, echo "Hi there!"
, etc.).
Un tel code ne doit produire une sortie que sur des connexions interactives, lorsqu'il est
tty
associé à une entrée standard. S'il ne fait pas ce test, il insérera ces messages texte là où ils n'appartiennent pas: dans ce cas, pollue le flux de protocole entre scp2
/ sftp
et sftp-server
.
La raison pour laquelle les fichiers de démarrage du shell sont pertinents, c'est que sshd
le shell de l'utilisateur est
utilisé lors du démarrage de tout programme pour le compte de l'utilisateur (en utilisant, par exemple, / bin / sh -c "commande"). C’est une tradition Unix qui présente des avantages:
- La configuration habituelle de l'utilisateur (alias de commande, variables d'environnement, umask, etc.) est effective lors de l'exécution de commandes à distance.
- La pratique courante consistant à définir le shell d'un compte sur / bin / false pour le désactiver empêchera le propriétaire d'exécuter des commandes, si l'authentification réussissait encore par accident pour une raison quelconque.
Détails du protocole SCP
Pour les personnes intéressées par le fonctionnement de SCP, j'ai trouvé des informations intéressantes dans Fonctionnement du protocole SCP, notamment des informations sur Exécution de scp avec des profils de shell parlants du côté distant. :
Par exemple, cela peut arriver si vous ajoutez ceci à votre profil shell sur le système distant:
écho ""
Pourquoi ça pend juste? Cela vient de la manière dont scp
en la source en mode attend la confirmation du premier message de protocole. S'il ne s'agit pas de 0 binaire, il s'attend à ce qu'il s'agisse d'une notification d'un problème distant et attend que davantage de caractères forment un message d'erreur jusqu'à ce que la nouvelle ligne arrive. Comme vous n'avez pas imprimé une nouvelle ligne après la première, votre section locale scp
reste dans une boucle bloquée read(2)
. Dans l'intervalle, après le traitement du profil de shell côté distant, le scp
mode récepteur a été démarré, mais celui-ci se bloque également read(2)
, dans l'attente d'un zéro binaire indiquant le début du transfert de données.
Conclusion / TLDR
La plupart des instructions typiques .bashrc
ne sont utiles que pour un shell interactif - pas lors de l'exécution de commandes distantes avec rsh
ou ssh
. Dans la plupart des situations de ce type, il n'est pas souhaitable de définir des variables de shell, des alias et des fonctions, et l'impression de texte sur une sortie standard est dangereuse pour le transfert de fichiers à l'aide de programmes tels que scp
ou sftp
. Quitter après avoir vérifié que le shell actuel est non interactif est le comportement le plus sûr .bashrc
.