Lors de la tentative de source d'un fichier, ne voudriez-vous pas une erreur indiquant que le fichier n'existe pas afin que vous sachiez quoi corriger?
Par exemple, nvm recommande d'ajouter ceci à votre profil / rc:
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
Avec ci-dessus, s'il nvm.sh
n'existe pas, vous obtiendrez une "erreur silencieuse". Mais si vous essayez . "$NVM_DIR/nvm.sh"
, la sortie sera FILE_PATH: No such file or directory
.
shell-script
JBallin
la source
la source
HOME
.Réponses:
Dans les shells POSIX,
.
est une fonction intégrée spéciale, donc son échec provoque la fermeture du shell (dans certains shells commebash
, cela n'est fait qu'en mode POSIX).Ce qui constitue une erreur dépend du shell. Tous ne se terminent pas sur une erreur de syntaxe lors de l'analyse du fichier, mais la plupart se fermeraient lorsque le fichier source ne peut pas être trouvé ou ouvert. Je n'en connais aucun qui se terminerait si la dernière commande du fichier source renvoyait avec un état de sortie différent de zéro (sauf si l'
errexit
option est bien sûr activée).Voici faire:
Est un cas où vous souhaitez source le fichier s'il est là, et pas si ce n'est pas le cas (ou est vide ici avec
-s
).Autrement dit, il ne doit pas être considéré comme une erreur (erreur fatale dans les shells POSIX) si le fichier n'est pas là, ce fichier est considéré comme un fichier facultatif.
Ce serait toujours une erreur (fatale) si le fichier n'était pas lisible ou était un répertoire ou (dans certains shells) s'il y avait une erreur de syntaxe lors de son analyse, ce qui serait de vraies conditions d'erreur qui devraient être signalées.
Certains diront qu'il y a une condition de concurrence. Mais la seule chose que cela signifie serait que le shell se termine avec une erreur si le fichier est supprimé entre le
[
et.
, mais je dirais qu'il est valide de considérer comme une erreur que ce fichier de chemin fixe disparaîtrait soudainement pendant que le script est fonctionnement.D'autre part,
où
command
¹ supprime l' attribut spécial de la.
commande (pour ne pas quitter le shell en cas d'erreur) ne fonctionnerait pas comme:.
les erreurs mais aussi les erreurs des commandes exécutées dans le fichier sourceD'autres syntaxes courantes (voir par exemple
grep -r /etc/default /etc/init*
sur les systèmes Debian pour les scripts d'initialisation qui n'ont pas encore été convertissystemd
(oùEnvironmentFile=-/etc/default/service
est utilisé à la place pour spécifier un fichier d'environnement facultatif)) incluent:[ -e "$file" ] && . "$file"
Vérifiez le fichier qu'il est là, toujours source s'il est vide. Erreur toujours fatale si elle ne peut pas être ouverte (même si elle est là ou était là). Vous pouvez voir plus de variantes comme
[ -f "$file" ]
(existe et est un fichier normal ),[ -r "$file" ]
(est lisible), ou des combinaisons de ceux-ci.[ ! -e "$file" ] || . "$file"
Une version légèrement meilleure. Il est plus clair que le fichier inexistant est un cas OK. Cela signifie également que
$?
reflétera l'état de sortie de la dernière commande exécutée$file
(dans le cas précédent, si vous obtenez1
, vous ne savez pas si c'est parce qu'il$file
n'existait pas ou si cette commande a échoué).command . "$file"
Attendez-vous à ce que le fichier soit là, mais ne quittez pas s'il ne peut pas être interprété.
[ ! -e "$file" ] || command . "$file"
Combinaison de ce qui précède: c'est OK si le fichier n'est pas là, et pour les shells POSIX, les échecs d'ouverture (ou d'analyse) du fichier sont signalés mais ne sont pas fatals (ce qui peut être plus souhaitable pour
~/.profile
).¹ Remarque: Dans,
zsh
cependant, vous ne pouvez pas utilisercommand
comme ça, sauf ensh
émulation; noter que dans le shell Korn,source
est en fait un alias pourcommand .
, une variante non spéciale de.
la source
.bash_profile
. Je suppose qu'il vaut mieux prévenir que guérir, mais bash est-il toujours en mode POSIX quand.bash_profile
est-il sourced?bash
mode POSIX. Vous voudriez[ -e /file ] && . /file
si vous ne le considérez pas comme une erreur lorsque le fichier n'existe pas. La source d'essai gère ensuite l'erreur, si aucune ne peut être effectuée ici..
signalera déjà une erreur (sur stderr). Et si l'intention est de ne pas le considérer comme une erreur lorsque le fichier n'existe pas, ce n'est pas correct (et il n'est pas possible, à partir de l'état de sortie, de dire s'il a.
échoué parce que le fichier n'existait pas ou n'était pas lisible ou était pas analysable, ou la dernière commande a échoué) qui sont les points que je fais ici dans cette réponse.Maintien de
nvm
la réponse de:Mon interprétation (combinée à l'excellente explication de Stéphane et au commentaire de Kusalananda):
C'est plus simple et plus sûr.
Il se défend contre les shells POSIX se fermant au démarrage en raison d'un fichier manquant (pour diverses raisons). Ceux qui utilisent des shells non POSIX (par exemple bash) peuvent supprimer le conditionnel s'ils préfèrent.
la source
/etc
, cela permet à certains utilisateurs d'avoir le fichier, et d'autres non. À mon humble avis, lanvm
réponse du responsable ne touche qu'à un seul aspect.Comme l' ont souligné JBallin et Stéphane Chazelas , dans les shells POSIX, le sourcing d'un fichier qui n'existe pas entraînerait l'échec de la connexion.
Mais l'ajout d'un test pour voir si le fichier existe et ensuite essayer de le source peut provoquer quelque chose appelé une condition de concurrence critique. Si quelque chose change
nvm.sh
entre le[ -s nvm.sh ]
et le. nvm.sh
, cela causera exactement le bogue qu'ils essaient d'empêcher, quoique beaucoup plus rarement.En général, le moyen d'empêcher les conditions de concurrence est simplement d'essayer la chose que vous voulez faire, puis de gérer l'erreur en cas d'échec, par exemple
Il s'avère que cela ne fonctionne pas dans les shells POSIX, car, comme ci-dessus, l'
.
échec entraînera la fermeture immédiate du shell, avant que la gestion des erreurs puisse s'exécuter.Ma réponse soutient que les shells POSIX ne sont pas pertinents pour cette question, car
.bash_profile
ils ne devraient jamais fonctionner en mode POSIX. Nous pouvons donc simplement faire le code ci-dessus de toute façon.Pour être plus sûr, nous pourrions nous assurer que le mode POSIX n'est pas en vigueur, ou que le mode POSIX est désactivé en utilisant la technique décrite dans /unix//a/383581/3169 .
La réponse de Stéphane contient quelques suggestions utiles sur la façon de gérer tous les shells POSIX, ce qui, je pense, était l'intention de l'auteur du nvm, mais était subtilement différent de ce que la question ici demandait, c'est pourquoi nous avons plusieurs approches possibles, en fonction de votre objectif. .
la source