Je voudrais un moyen d'ajouter des choses à $ PATH, à l'échelle du système ou pour un utilisateur individuel, sans potentiellement ajouter plusieurs fois le même chemin.
Une raison de vouloir le faire est que des ajouts puissent être effectués .bashrc
, qui ne nécessitent pas de connexion, et sont également plus utiles sur les systèmes qui utilisent (par exemple) lightdm
, qui n'appelle jamais .profile
.
Je connais des questions sur la façon de nettoyer les doublons de $ PATH, mais je ne veux pas supprimer les doublons . Je voudrais un moyen d' ajouter des chemins uniquement s'ils ne sont pas déjà présents.
Réponses:
Supposons que le nouveau chemin que nous voulons ajouter soit:
Ensuite, en utilisant n'importe quel shell POSIX, nous pouvons tester pour voir s'il
new
est déjà dans le chemin et l'ajouter s'il ne l'est pas:Notez l'utilisation de deux points. Sans les deux points, nous pourrions penser que, disons,
new=/bin
était déjà sur le chemin parce que le modèle correspondait/usr/bin
. Alors que les CHEMINS comportent normalement de nombreux éléments, les cas particuliers de zéro et d'un élément dans le CHEMIN sont également traités. Le cas du chemin ayant un premier pas d' éléments (étant vide) est assurée par l'utilisation de${PATH:=$new}
qui attribuePATH
à$new
si elle est vide. La définition de valeurs par défaut pour les paramètres de cette manière est une caractéristique de tous les shells POSIX: voir la section 2.6.2 de la documentation POSIX .)Une fonction appelable
Pour plus de commodité, le code ci-dessus peut être mis dans une fonction. Cette fonction peut être définie sur la ligne de commande ou, pour la rendre disponible en permanence, insérée dans le script d'initialisation de votre shell (pour les utilisateurs bash, ce serait
~/.bashrc
):Pour utiliser cette fonction de mise à jour de chemin d'accès pour ajouter un répertoire au PATH actuel:
la source
PATH
est vide, cela ajoutera une entrée vide (c'est-à-dire le répertoire courant) auPATH
. Je pense que vous avez besoin d'un autre cas.case
. Faites-lecase "${PATH:=$new}"
. Voir ma propre réponse pour des solutions de rechange similaires.Créez un fichier
/etc/profile.d
appelé, par exemple,mypath.sh
(ou ce que vous voulez). Si vous utilisez lightdm, assurez-vous que c'est viable ou bien utilisez/etc/bashrc
ou un fichier provenant de celui-ci. Ajoutez à cela les fonctions suivantes:Les choses au début de (précédé de) $ PATH ont priorité sur ce qui suit, et inversement, les choses à la fin (ajoutées) seront remplacées par ce qui précède. Cela signifie que si votre $ PATH est
/usr/local/bin:/usr/bin
et qu'il y a un exécutablegotcha
dans les deux répertoires, celui de/usr/local/bin
sera utilisé par défaut.Vous pouvez maintenant - dans ce même fichier, dans un autre fichier de configuration du shell ou depuis la ligne de commande - utiliser:
Si c'est dans un
.bashrc
, cela empêchera la valeur d'apparaître plus d'une fois lorsque vous démarrez un nouveau shell. Il y a une limitation en ce que si vous voulez ajouter quelque chose qui a été ajouté (c'est-à-dire déplacer un chemin dans $ PATH) ou vice versa, vous devrez le faire vous-même.la source
$PATH
avecIFS=:
est finalement plus flexible quecase
.case
, OMI. J'imagine qu'onawk
pourrait en faire bon usage ici aussi.gawk
pourrait directement attribuer$PATH
.Vous pouvez le faire de cette façon:
Remarque: si vous créez PATH à partir d'autres variables, vérifiez qu'elles ne sont pas vides, car de nombreux shells interprètent "" comme "". .
la source
-q
requise par POSIX pour grep, mais je ne sais pas si cela signifie qu'il y a encore des greps (non POSIX) qui ne l'ont pas./my/bin
La partie importante du code est de vérifier s'il
PATH
contient un chemin spécifique:Autrement dit, assurez-vous que chaque chemin d'accès
PATH
est délimité des deux côtés par lePATH
séparateur (:
), puis vérifiez (-q
) si la chaîne littérale (-F
) constituée d'unPATH
séparateur, de votre chemin d'accès et d'un autrePATH
séparateur existe à l'intérieur. Si ce n'est pas le cas, vous pouvez ajouter le chemin en toute sécurité:Cela devrait être compatible POSIX et devrait fonctionner avec tout chemin ne contenant pas de caractère de nouvelle ligne. C'est plus complexe si vous voulez qu'il fonctionne avec des chemins contenant des sauts de ligne tout en étant compatible POSIX, mais si vous en avez un
grep
qui le prend en charge,-z
vous pouvez l'utiliser.la source
Je porte cette petite fonction avec moi dans divers
~/.profile
fichiers depuis des années. Je pense qu'il a été écrit par l'administrateur système dans un laboratoire dans lequel je travaillais, mais je ne suis pas sûr. Quoi qu'il en soit, il est similaire à l'approche de Goldilock mais légèrement différent:Donc, pour ajouter un nouveau répertoire au début de la
PATH
:et à la fin:
la source
/bin/grep
->grep
MISE À JOUR:
J'ai remarqué que votre propre réponse avait une fonction distincte pour chaque ajout ou ajout au
$PATH
. J'ai aimé l'idée. J'ai donc ajouté un petit traitement des arguments. Je l'ai également correctement_
nommé:SORTIE:
Par défaut, il
-A
dépendra de$PATH
, mais vous pouvez modifier ce comportement pour qu'il se-P
répète en ajoutant un-P
n'importe où dans votre liste d'arguments. Vous pouvez le remettre en-A
attente en lui remettant un-A
.ÉVALUATION SÉCURITAIRE
Dans la plupart des cas, je recommande aux gens d'éviter toute utilisation de
eval
. Mais cela, je pense, se démarque comme un exemple de son utilisation pour de bon. Dans ce cas, la seule déclaration que vouseval
pouvez voir estP=
ouA=
. Les valeurs de ses arguments sont strictement testées avant d'être appelée. C'est pour çaeval
.Cela acceptera autant d'arguments que vous le donnerez et n'en ajoutera chacun
$PATH
qu'une seule fois et seulement s'il n'est pas déjà dedans$PATH
. Il utilise uniquement un script shell POSIX entièrement portable, ne s'appuie que sur des shell intégrés et est très rapide.la source
_
préfixage des fonctions de shell les rend "correctement espacées"? Dans d'autres langues, cela indique généralement une fonction globale interne (c'est-à-dire une fonction qui doit être globale, mais qui n'est pas destinée à être utilisée en externe dans le cadre d'une API). Mes noms ne sont certainement pas d'excellents choix, mais il me semble que l'utilisation_
ne résout pas du tout les problèmes de collision - il serait préférable de s'attaquer à un espace de noms réel, par exemple.mikeserv_path_assign()
._
vous devez changer de gestionnaire de package. Dans tous les cas, c'est essentiellement une fonction "globale, interne" - elle est globale pour chaque shell invoqué depuis le shell dans lequel elle est déclarée, et ce n'est qu'un peu de script de langage interprété qui traîne dans la mémoire de l'interpréteur . unix.stackexchange.com/questions/120528/…unset a
(ou équivalent) à la fin du profil?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:Préparez-vous à la gloire instantanée. Ensuite, plutôt que de le faire et en espérant le meilleur:
Faites-le à la place et soyez assuré d'obtenir le meilleur, que vous le vouliez vraiment ou non:
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 formulaireexport PATH=$PATH:~/opt/bin
invitent à des complications diaboliques avec:Noms de répertoires accidentellement relatifs (par exemple,
export PATH=$PATH:opt/bin
). Alors quebash
et enzsh
silence acceptent et ignorent la plupart du temps les noms relatifs dans la plupart des cas, les noms relatifs préfixés par l'unh
ou l' autret
(et peut-être d'autres personnages néfastes) font mutuellement honte de se mutiler ala Masaki Kobayashi, chef-d'œuvre de 1962, Harakiri :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 commeexport PATH=$PATH:~/wat
explosent rapidement dans le septième cercle de l'${PATH}
enferPATH=/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. )${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 parbash
etzsh
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: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
etzsh
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 paradd_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:Notez le
*":${dirname:A}:"*
plutôt que*":${dirname}:"*
l'original.:A
est un merveilleuxzsh
-isme malheureusement absent sous la plupart des autres obus - y comprisbash
. Pour citerman zshexpn
:Pas d'autres questions.
De rien. Profitez de bombardements en toute sécurité. Vous le méritez maintenant.
la source
Voici ma version de style de programmation fonctionnelle.
*PATH
variable délimitée par deux points , pas seulementPATH
.A noter également:
export
ing; c'est à l'appelant (voir les exemples)bash
; pas de bifurcationla source
Ce script vous permet d'ajouter à la fin de
$PATH
:Ou ajoutez au début de
$PATH
:la source