Sur mon installation Arch, /etc/bash.bashrc
et /etc/skel/.bashrc
contenir ces lignes :
# If not running interactively, don't do anything
[[ $- != *i* ]] && return
Sur Debian, /etc/bash.bashrc
a :
# If not running interactively, don't do anything
[ -z "$PS1" ] && return
Et /etc/skel/.bashrc
:
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac
D'après man bash
, cependant, les shells non interactifs ne lisent même pas ces fichiers :
When bash is started non-interactively, to run a shell script, for
example, it looks for the variable BASH_ENV in the environment, expands
its value if it appears there, and uses the expanded value as the name
of a file to read and execute. Bash behaves as if the following com‐
mand were executed:
if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi
but the value of the PATH variable is not used to search for the file‐
name.
Si je comprends bien, le *.bashrc
les fichiers ne seront lus que si BASH_ENV
est configuré pour pointer vers eux. C'est quelque chose qui ne peut pas arriver par hasard et ne se produira que si quelqu'un a explicitement défini la variable en conséquence.
Cela semble briser la possibilité que des scripts sourcent le .bashrc
d'un utilisateur automatiquement en définissant BASH_ENV
, quelque chose qui pourrait être utile. Étant donné que bash ne lira jamais ces fichiers lorsqu'il est exécuté de manière non interactive, sauf indication explicite de le faire, pourquoi la valeur par défaut *bashrc
fichiers l'interdisent ?
Réponse acceptée :
C'est une question que j'allais poster ici il y a quelques semaines. Comme terdon , j'ai compris qu'un .bashrc
ne provient que des shells Bash interactifs, il ne devrait donc pas y avoir besoin de .bashrc
pour vérifier s'il s'exécute dans un shell interactif. Confusément, tous les distributions que j'utilise (Ubuntu, RHEL et Cygwin) avaient un certain type de vérification (test $-
ou $PS1
) pour s'assurer que le shell actuel est interactif. Je n'aime pas la programmation culte du cargo, alors j'ai commencé à comprendre le but de ce code dans mon .bashrc
.
Bash a un cas particulier pour les shells distants
Après avoir étudié le problème, j'ai découvert que les shells distants sont traités différemment. Bien que les shells Bash non interactifs n'exécutent normalement pas ~/.bashrc
commandes au démarrage, un cas particulier est fait lorsque le shell est appelé par un 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éralementrshd
, 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 si
invoqué en tant quesh
. Le--norc
l'option peut être utilisée pour inhiber ce comportement,
et le--rcfile
l'option peut être utilisée pour forcer la lecture d'un autre fichier, mais
nirshd
nisshd
invoquez généralement le shell avec ces options ou
autorisez-les à être spécifiées.
Exemple
Insérez ce qui suit au début d'un .bashrc
distant . (Si .bashrc
provient de .profile
ou .bash_profile
, désactivez-le temporairement pendant le test) :
echo bashrc
fun()
{
echo functions work
}
Exécutez les commandes suivantes localement :
$ ssh remote_host 'echo $- $0'
bashrc
hBc bash
- Non
i
en$-
indique que le shell est non interactif . - Pas de début
-
en$0
indique que le shell n'est pas un shell de connexion .
Fonctions Shell définies dans le .bashrc
distant peut également être exécuté :
$ ssh remote_host fun
bashrc
functions work
J'ai remarqué que le ~/.bashrc
est seulement source lorsqu'une commande est spécifiée comme argument pour ssh
. Cela a du sens :lorsque ssh
est utilisé pour démarrer un shell de connexion normal, .profile
ou .bash_profile
sont exécutés (et .bashrc
n'est sourcée que si cela est explicitement fait par l'un de ces fichiers).
Le principal avantage que je peux voir d'avoir .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 dans un .bashrc
typique ne sont pertinents que dans un shell interactif, par exemple, les alias ne sont pas développés à moins que le shell ne soit 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 les 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 scp
commande. Il n'y a aucune mention de cela dans la page de manuel - seulement une mention que scp
utilise ssh
pour son transfert de données. Cela a pour conséquence que si le .bashrc
contient toutes les commandes qui impriment sur la sortie standard, les transferts de fichiers échoueront , par exemple, scp échoue sans erreur.
Pourquoi scp
et sftp
échouer
SCP (Secure copy) et SFTP (Secure File Transfer Protocol) ont leurs propres protocoles pour que les extrémités locales et distantes échangent des informations sur le(s) fichier(s) en cours de transfert. Tout texte inattendu provenant de l'extrémité distante est (à tort) interprété comme faisant partie du protocole et le transfert échoue. D'après une FAQ du Snail Book
Ce qui arrive souvent, cependant, c'est qu'il y a des instructions dans les fichiers de démarrage
du système ou du shell par utilisateur sur le serveur (.bashrc
,.profile
,/etc/csh.cshrc
,.login
, etc.) qui génèrent des messages texte lors de la connexion,
destinés à être lus par des humains (commefortune
,echo "Hi there!"
, etc.).Un tel code ne devrait produire une sortie que sur les connexions interactives, lorsqu'il existe un
tty
attaché à l'entrée standard. S'il ne fait pas ce test, il va
insérer ces messages texte là où ils n'ont pas leur place :dans ce cas, polluant
le flux de protocole entrescp2
/sftp
etsftp-server
.La raison pour laquelle les fichiers de démarrage du shell sont pertinents, c'est que
sshd
utilise le shell de l'utilisateur lors du démarrage de tout programme au nom de l'utilisateur (en utilisant par exemple /bin/sh -c "commande"). Il s'agit d'une tradition Unix, et présente
des avantages :
- La configuration habituelle de l'utilisateur (alias de commande, variables d'environnement, umask,
etc.) s'applique lorsque les commandes à distance sont exécutées.- La pratique courante consistant à définir le shell d'un compte sur /bin/false pour désactiver
cela empêchera le propriétaire d'exécuter des commandes, si l'authentification
réussissait toujours accidentellement pour une raison quelconque.
Détails du protocole SCP
Pour ceux qui s'intéressent aux détails du fonctionnement de SCP, j'ai trouvé des informations intéressantes dans Comment fonctionne le protocole SCP, qui inclut des détails sur Exécuter scp avec des profils de shell bavards du côté distant ? :
Par exemple, cela peut se produire si vous ajoutez ceci à votre profil shell sur le
système distant :echo ""
Pourquoi ça bloque ? Cela vient de la façon dont
scp
dans source mode
attend la confirmation du premier message de protocole. S'il n'est pas binaire
0, il s'attend à ce qu'il s'agisse d'une notification d'un problème distant et attend
d'autres caractères pour former un message d'erreur jusqu'à ce que la nouvelle ligne arrive. Puisque
vous n'avez pas imprimé une autre nouvelle ligne après la première, votrescp
local juste
reste dans une boucle, bloqué surread(2)
. En attendant, une fois le profil du shell
traité du côté distant,scp
en mode récepteur a été démarré,
qui bloque également surread(2)
, attendant un zéro binaire indiquant le début
du transfert de données.
Conclusion / TLDR
La plupart des déclarations dans un .bashrc
typique ne sont utiles que pour un shell interactif - pas lors de l'exécution de commandes distantes avec rsh
ou ssh
. Dans la plupart de ces situations, la définition de variables shell, d'alias et de fonctions de définition n'est pas souhaitée - et l'impression de n'importe quel texte vers la sortie standard est activement nuisible si le transfert de fichiers à l'aide de programmes tels que scp
ou sftp
. Quitter après avoir vérifié que le shell actuel n'est pas interactif est le comportement le plus sûr pour .bashrc
.