Voir! La fonction de coque portable 12 lignes ... techniquement bash et zsh portable qui aime avec dévouement votre script de démarrage ~/.bashrc
ou ~/.zshrc
de choix:
# void +path.append(str dirname, ...)
#
# Append each passed existing directory to the current user's ${PATH} in a
# safe manner silently ignoring:
#
# * Relative directories (i.e., *NOT* prefixed by the directory separator).
# * Duplicate directories (i.e., already listed in the current ${PATH}).
# * Nonextant directories.
+path.append() {
# For each passed dirname...
local dirname
for dirname; do
# Strip the trailing directory separator if any from this dirname,
# reducing this dirname to the canonical form expected by the
# test for uniqueness performed below.
dirname="${dirname%/}"
# If this dirname is either relative, duplicate, or nonextant, then
# silently ignore this dirname and continue to the next. Note that the
# extancy test is the least performant test and hence deferred.
[[ "${dirname:0:1}" == '/' &&
":${PATH}:" != *":${dirname}:"* &&
-d "${dirname}" ]] || continue
# Else, this is an existing absolute unique dirname. In this case,
# append this dirname to the current ${PATH}.
PATH="${PATH}:${dirname}"
done
# Strip an erroneously leading delimiter from the current ${PATH} if any,
# a common edge case when the initial ${PATH} is the empty string.
PATH="${PATH#:}"
# Export the current ${PATH} to subprocesses. Although system-wide scripts
# already export the ${PATH} by default on most systems, "Bother free is
# the way to be."
export PATH
}
Préparez-vous à la gloire instantanée. Ensuite, plutôt que de le faire et en espérant le meilleur:
export PATH=$PATH:~/opt/bin:~/the/black/goat/of/the/woods/with/a/thousand/young
Faites-le à la place et soyez assuré d'obtenir le meilleur, que vous le vouliez vraiment ou non:
+path.append ~/opt/bin ~/the/black/goat/of/the/woods/with/a/thousand/young
Très bien, définissez «le meilleur».
Ajouter et ajouter en toute sécurité au courant ${PATH}
n'est pas l'affaire banale qu'il est communément établi. Bien que pratiques et apparemment sensées, les lignes simples du formulaire export PATH=$PATH:~/opt/bin
invitent à des complications diaboliques avec:
Noms de répertoires accidentellement relatifs (par exemple, export PATH=$PATH:opt/bin
). Alors que bash
et en zsh
silence acceptent et ignorent la plupart du temps les noms relatifs dans la plupart des cas, les noms relatifs préfixés par l'un h
ou l' autre t
(et peut-être d'autres personnages néfastes) font mutuellement honte de se mutiler ala Masaki Kobayashi, chef-d'œuvre de 1962, Harakiri :
# Don't try this at home. You will feel great pain.
$ PATH='/usr/local/bin:/usr/bin:/bin' && export PATH=$PATH:harakiri && echo $PATH
/usr/local/bin:/usr/bin:arakiri
$ PATH='/usr/local/bin:/usr/bin:/bin' && export PATH=$PATH:tanuki/yokai && echo $PATH
binanuki/yokai # Congratulations. Your system is now face-up in the gutter.
Duplication accidentelle de noms de répertoires. Bien que les ${PATH}
noms de répertoires en double soient en grande partie inoffensifs, ils sont également indésirables, encombrants, légèrement inefficaces, entravent le débogage et favorisent l'usure du lecteur - en quelque sorte comme cette réponse. Alors que les SSD de style NAND sont ( bien sûr ) à l'abri de l'usure en lecture, les disques durs ne le sont pas. L'accès inutile au système de fichiers à chaque tentative de commande implique une usure inutile de la tête de lecture au même tempo. Les doublons sont particulièrement onctueux lors de l'invocation de coquilles imbriquées dans des sous-processus imbriqués, à ce moment-là, des lignes uniformes apparemment inoffensives comme export PATH=$PATH:~/wat
explosent rapidement dans le septième cercle de l' ${PATH}
enfer PATH=/usr/local/bin:/usr/bin:/bin:/home/leycec/wat:/home/leycec/wat:/home/leycec/wat:/home/leycec/wat
. Seul Beelzebubba peut vous aider si vous ajoutez ensuite des noms de répertoires supplémentaires à cela. (Ne laissez pas cela arriver à vos précieux enfants. )
- Répertoires manquants accidentellement. Encore une fois, bien que les
${PATH}
noms manquants soient en grande partie inoffensifs, ils sont également généralement indésirables, encombrants, légèrement inefficaces, entravent le débogage et favorisent l'usure du lecteur.
Ergo, automatisation conviviale comme la fonction shell définie ci-dessus. Nous devons nous sauver de nous-mêmes.
Mais ... Pourquoi "+ path.append ()"? Pourquoi pas simplement append_path ()?
Pour disambiguity (par exemple, avec des commandes externes dans le courant de ${PATH}
fonctions ou à l' échelle du système shell définies ailleurs) fonctions, shell définies par l' utilisateur sont idéalement préfixés ou suffixé avec des sous - chaînes uniques pris en charge par bash
et zsh
mais par ailleurs interdit de commande standard des noms de base - comme, par exemple, +
.
Hey. Ça marche. Ne me jugez pas.
Mais ... Pourquoi "+ path.append ()"? Pourquoi pas "+ path.prepend ()"?
Parce que l'ajout au courant ${PATH}
est plus sûr que l'ajout au courant ${PATH}
, toutes choses étant égales par ailleurs, ce qu'elles ne sont jamais. Remplacer les commandes à l'échelle du système par des commandes spécifiques à l'utilisateur peut être au mieux insalubre et au pire rendre fou. Sous Linux, par exemple, les applications en aval attendent généralement les variantes de commandes GNU coreutils plutôt que des dérivés ou alternatives non standard personnalisés.
Cela dit, il existe absolument des cas d'utilisation valables pour le faire. La définition de la +path.prepend()
fonction équivalente est triviale. Nébulosité sans prolixe, pour sa santé mentale partagée:
+path.prepend() {
local dirname
for dirname in "${@}"; do
dirname="${dirname%/}"
[[ "${dirname:0:1}" == '/' &&
":${PATH}:" != *":${dirname}:"* &&
-d "${dirname}" ]] || continue
PATH="${dirname}:${PATH}"
done
PATH="${PATH%:}"
export PATH
}
Mais ... Pourquoi pas Gilles?
La réponse acceptée par Gilles ailleurs est remarquablement optimale dans le cas général en tant qu ' «appendice idempotent agnostique à la coque» . Dans le cas commun bash
et zsh
avec aucun des liens symboliques indésirables, cependant, la pénalité de performance nécessaire pour le faire attriste le ricer Gentoo en moi. Même en présence de liens symboliques indésirables, il est discutable de savoir si la création d'un sous-shell par add_to_PATH()
argument vaut l'insertion potentielle de doublons de liens symboliques.
Pour les cas d'utilisation stricts exigeant que même les doublons de liens symboliques soient éliminés, cette zsh
variante spécifique le fait via des fonctions intégrées efficaces plutôt que des fourches inefficaces:
+path.append() {
local dirname
for dirname in "${@}"; do
dirname="${dirname%/}"
[[ "${dirname:0:1}" == '/' &&
":${PATH}:" != *":${dirname:A}:"* &&
-d "${dirname}" ]] || continue
PATH="${PATH}:${dirname}"
done
PATH="${PATH#:}"
export PATH
}
Notez le *":${dirname:A}:"*
plutôt que *":${dirname}:"*
l'original. :A
est un merveilleux zsh
-isme malheureusement absent sous la plupart des autres obus - y compris bash
. Pour citer man zshexpn
:
R : Transformez un nom de fichier en chemin absolu comme le a
fait le modificateur, puis passez le résultat via la realpath(3)
fonction de bibliothèque pour résoudre les liens symboliques. Remarque: sur les systèmes qui n'ont pas de realpath(3)
fonction de bibliothèque, les liens symboliques ne sont pas résolus, donc sur ces systèmes a
et A
sont équivalents.
Pas d'autres questions.
De rien. Profitez de bombardements en toute sécurité. Vous le méritez maintenant.