Comment ajouter correctement un chemin à PATH?

922

Je me demande où un nouveau chemin doit être ajouté à la PATHvariable d'environnement. Je sais que cela peut être accompli en éditant .bashrc(par exemple), mais on ne sait pas comment faire cela.

Par ici:

export PATH=~/opt/bin:$PATH

ou ca?

export PATH=$PATH:~/opt/bin
Paolo
la source
printf '\ nPATH = $ PATH: "chemin d'accès pour ajouter" \ nexport PATH \ n' >> ~ / .bashrc
Sudoer
S'il y a déjà quelques chemins ajoutés, par exemple PATH=$PATH:$HOME/.local/bin:$HOME/bin, un autre peut être ajouté en séparant avec: par exemple PATH=$PATH:$HOME/.local/bin:$HOME/bin:/home/ec2-user/pear/bin.
Sandeepan Nath
2
Ces réponses fonctionnent-elles pour tous les goûts de Linux?
Ungeheuer

Réponses:

1032

Le truc simple

PATH=$PATH:~/opt/bin

ou

PATH=~/opt/bin:$PATH

selon que vous voulez ajouter ~/opt/binà la fin (à rechercher après tous les autres répertoires, s'il existe un programme du même nom dans plusieurs répertoires) ou au début (à rechercher avant tous les autres répertoires).

Vous pouvez ajouter plusieurs entrées en même temps. PATH=$PATH:~/opt/bin:~/opt/node/binou des variations sur le travail de commande très bien. Ne mettez pas de ligne exportau début de la ligne car il y a des complications supplémentaires (voir ci-dessous «Notes sur les coquillages autres que bash»).

Si votre PATHstructure est construite à partir de nombreux composants différents, vous risquez de vous retrouver avec des entrées en double. Voir Comment ajouter le chemin du répertoire de départ à découvrir par la commande Unix? et Supprimez les entrées $ PATH en double avec la commande awk pour éviter d’ajouter ou de supprimer les doublons.

Certaines distributions ajoutent automatiquement ~/binvotre PATH s'il existe, d'ailleurs.

Où le mettre

Mettez la ligne à modifier PATHdans ~/.profile, ou ~/.bash_profilesi c'est ce que vous avez.

Notez que ce programme ~/.bash_rcn’est lu par aucun programme. Il ~/.bashrcs’agit du fichier de configuration des instances interactives de bash. Vous ne devez pas définir de variables d’environnement dans ~/.bashrc. Le bon endroit pour définir les variables d'environnement telles que PATHest ~/.profile(ou ~/.bash_profilesi vous ne vous souciez pas des shells autres que bash). Voir Quelle est la différence entre eux et lequel devrais-je utiliser?

Ne le mettez pas /etc/environmentou ~/.pam_environment: ce ne sont pas des fichiers shell, vous ne pouvez pas utiliser de substitutions comme $PATHici. Dans ces fichiers, vous ne pouvez que remplacer une variable, pas l’ajouter.

Complications potentielles dans certains scripts système

Vous n'avez pas besoin exportsi la variable est déjà dans l'environnement: toute modification de la valeur de la variable est reflétée dans l'environnement.¹ PATHest presque toujours dans l'environnement; tous les systèmes Unix le configurent très tôt (généralement lors du tout premier processus).

Au moment de la connexion, vous pouvez compter sur votre PATHprésence déjà dans l'environnement et sur certains répertoires système. Si vous écrivez un script qui peut être exécuté tôt lors de la configuration d'un environnement virtuel, vous devrez peut-être vous assurer qu'il PATHest non vide et exporté: si PATHest toujours non PATH=$PATH:/some/directorydéfini , quelque chose comme serait défini PATHsur :/some/directory, et le composant vide au début signifie le répertoire en cours (comme .:/some/directory).

if [ -z "${PATH-}" ]; then export PATH=/usr/local/bin:/usr/bin:/bin; fi

Notes sur les coquillages autres que bash

En bash, ksh et zsh, exportest une syntaxe spéciale, et les deux PATH=~/opt/bin:$PATHet export PATH=~/opt/bin:$PATHfont même la bonne chose. Dans d'autres shells de style Bourne / POSIX, tels que dash ( /bin/shsur de nombreux systèmes), exportest analysé comme une commande ordinaire, ce qui implique deux différences:

Ainsi, dans les shells comme dash, export PATH=~/opt/bin:$PATHdéfinit PATHla chaîne littérale ~/opt/bin/:suivie de la valeur PATHallant jusqu'au premier espace. PATH=~/opt/bin:$PATH(une affectation simple) ne nécessite pas de citations et fait la bonne chose. Si vous voulez utiliser exportdans un script portable, vous devez écrire export PATH="$HOME/opt/bin:$PATH", ou PATH=~/opt/bin:$PATH; export PATH(ou PATH=$HOME/opt/bin:$PATH; export PATHpour la portabilité même du shell Bourne qui n'a pas accepté export var=valueet n'a pas fait l'expansion du tilde).

¹ Ce n’était pas le cas dans les coquillages Bourne (comme dans le shell Bourne actuel, mais pas dans le style POSIX moderne), mais il est peu probable que vous rencontriez de tels coquillages de nos jours.

Gilles
la source
Toujours pas capable de comprendre la complication avec l'exportation. pouvez-vous s'il vous plaît le simplifier?
priojeet priyom
@priojeetpriyom Explication simple: vous n'avez pas besoin export.
Gilles le
Merci pour cette réponse, parfaitement détaillée. Vous dites " Vous ne devez pas définir de variables d'environnement dans ~ / .bashrc ", mais malheureusement, 100% des programmes que j'ai installés sur mon système et qui modifient le chemin d'accès (FZF et Rust's Cargo) modifient le chemin d'accès .bashrc. Je suppose que parce que FZF est écrit en rouille aussi, il suit le modèle de rouille.
icc97
83

Dans les deux cas, cela fonctionne, mais ils ne font pas la même chose: les éléments de PATHsont vérifiés de gauche à droite. Dans votre premier exemple, les exécutables de ~/opt/binont priorité sur ceux installés, par exemple dans /usr/bin, ce qui peut être ou ne pas être ce que vous voulez.

En particulier, du point de vue de la sécurité, il est dangereux d’ajouter des chemins au premier plan, car si quelqu'un peut obtenir un accès en écriture à votre ~/opt/bin, il peut, par exemple, en insérer un différent ls, que vous utiliseriez probablement à la place. de /bin/lssans remarquer. Maintenant, imaginez la même chose pour sshvotre navigateur ou votre choix ... (La même chose vaut pour mettre. Sur votre chemin.)

Ulrich Schwarz
la source
6
Mais si vous voulez avoir votre propre version personnalisée de ls, vous devez la mettre dans un répertoire avant /bin.
Barmar
16
ou alias ls = myls
waltinator
37

Je suis confus par la question 2 (depuis retirée de la question car elle était due à une question non liée):

Quelle est une méthode pratique pour ajouter plus de chemins sur différentes lignes? Au départ, j'ai pensé que cela pourrait faire l'affaire:

export PATH=$PATH:~/opt/bin
export PATH=$PATH:~/opt/node/bin

mais ce n'est pas le cas, car la deuxième affectation ne se limite pas à l'ajout ~/opt/node/bin, mais également à l'ensemble PATHprécédemment attribué.

C'est une solution possible:

export PATH=$PATH:~/opt/bin:~/opt/node/bin

mais pour des raisons de lisibilité, je préférerais avoir une affectation pour un chemin.

Si tu le dis

PATH=~/opt/bin

c'est tout ce qui sera dans votre CHEMIN. PATH est juste une variable d’environnement, et si vous voulez ajouter à PATH, vous devez reconstruire la variable avec exactement le contenu que vous voulez. C'est-à-dire que ce que vous donnez comme exemple à la question 2 correspond exactement à ce que vous voulez faire, à moins que je manque totalement le sens de la question.

J'utilise les deux formes dans mon code. J'ai un profil générique que j'installe sur chaque machine sur laquelle je travaille et qui ressemble à ceci, afin de prendre en charge les répertoires potentiellement manquants:

export PATH=/opt/bin:/usr/local/bin:/usr/contrib/bin:/bin:/usr/bin:/usr/sbin:/usr/bin/X11
# add optional items to the path
for bindir in $HOME/local/bin $HOME/bin; do
    if [ -d $bindir ]; then
        PATH=$PATH:${bindir}
    fi
done
Carl Cravens
la source
2
Vous avez raison à propos de l'exemple de la question 2, cela fonctionne. Un autre problème lié à PATH sur mon système m'a confondu. Désolé.
Paolo
26

La méthode à toute épreuve pour ajouter / préparer

Le choix de l'ajout ou de l'ajout au début dépend de nombreuses considérations. Beaucoup d’entre eux sont couverts par d’autres réponses, je ne les répéterai donc pas ici.

Un point important est que, même si les scripts système ne l'utilisent pas (je me demande pourquoi) * 1 , la méthode à toute épreuve pour ajouter un chemin (par exemple, $HOME/bin) à la variable d'environnement PATH est

PATH="${PATH:+${PATH}:}$HOME/bin"

pour ajouter (au lieu de PATH="$PATH:$HOME/bin") et

PATH="$HOME/bin${PATH:+:${PATH}}"

pour ajouter (au lieu de PATH="$HOME/bin:$PATH")

Cela évite les faux colon avant / arrière lorsqu’il $PATHest initialement vide, ce qui peut avoir des effets secondaires indésirables et peut devenir un cauchemar , difficile à trouver ( cette réponse traite brièvement du cas dans l’ awkavenir).

Explication (à partir de l’ extension des paramètres du shell ):

${parameter:+word}

Si parameterest nul ou non défini, rien n'est substitué, sinon l'expansion de wordest substituée.

Ainsi, ${PATH:+${PATH}:}est étendu à: 1) rien, si PATHest nul ou non défini , 2) ${PATH}:, si PATHest défini.

Note : Ceci est pour bash.


* 1 Je viens de constater que des scripts comme ceux-ci devtoolset-6/enableutilisent réellement cela,

$ cat /opt/rh/devtoolset-6/enable
# General environment variables
export PATH=/opt/rh/devtoolset-6/root/usr/bin${PATH:+:${PATH}}
...
sancho.s
la source
24

Linux détermine le chemin de recherche de l'exécutable avec la $PATHvariable d'environnement. Pour ajouter directory / data / myscripts au début de la $PATHvariable d'environnement, utilisez ce qui suit:

PATH=/data/myscripts:$PATH

Pour ajouter ce répertoire à la fin du chemin, utilisez la commande suivante:

PATH=$PATH:/data/myscripts

Mais les précédentes ne suffisent pas, car lorsque vous définissez une variable d'environnement dans un script, cette modification est effective uniquement dans le script. Il n'y a que deux manières de contourner cette limitation:

  • Si, dans le script, vous exportez la variable d’environnement, elle est effective dans tous les programmes appelés par le script. Notez qu'il n'est pas efficace dans le programme qui a appelé le script.
  • Si le programme qui appelle le script le fait par inclusion au lieu d'appeler, toute modification de l'environnement dans le script prend effet dans le programme appelant. Une telle inclusion peut être faite avec la commande dot ou la commande source.

Exemples:

$HOME/myscript.sh
source $HOME/myscript.sh

L'inclusion incorpore fondamentalement le script "appelé" dans le script "appelant". C'est comme un #include in C. Donc c'est efficace dans le script ou le programme "appelant". Mais bien sûr, cela n’est efficace dans aucun programme ou script appelé par le programme appelant. Pour la rendre efficace tout au long de la chaîne d'appels, vous devez suivre le paramétrage de la variable d'environnement avec une commande d'exportation.

Par exemple, le programme shell bash incorpore le contenu du fichier .bash_profile par inclusion. Placez les 2 lignes suivantes dans .bash_profile:

PATH=$PATH:/data/myscripts
export PATH

met efficacement ces 2 lignes de code dans le programme bash. Ainsi, dans bash, la variable $ PATH inclut $HOME/myscript.sh, et à cause de l'instruction export, tous les programmes appelés par bash ont la $PATHvariable modifiée . Et comme tous les programmes que vous exécutez à partir d'une invite bash sont appelés par bash, le nouveau chemin d'accès est en vigueur pour tout ce que vous exécutez à partir de l'invite bash.

En bout de ligne, pour ajouter un nouveau répertoire au chemin, vous devez l'ajouter ou le ajouter à la variable d'environnement $ PATH dans un script inclus dans le shell, et exporter la $PATHvariable d'environnement.

Plus d'informations ici

Steve Brown
la source
19

Depuis un certain temps maintenant , je l' ai gardé avec moi deux fonctions pathaddet pathrmqui aident à ajouter des éléments au chemin sans avoir à vous soucier de duplications.

pathaddprend un argument de chemin unique et un afterargument facultatif qui, s’il est fourni, sera ajouté à la valeur PATHsinon, il le précède.

Dans presque toutes les situations, si vous ajoutez des éléments au chemin, vous voudrez probablement remplacer tout ce qui se trouve déjà dans le chemin. C'est pourquoi j'opte d'utiliser l'ajout par défaut.

pathadd() {
    newelement=${1%/}
    if [ -d "$1" ] && ! echo $PATH | grep -E -q "(^|:)$newelement($|:)" ; then
        if [ "$2" = "after" ] ; then
            PATH="$PATH:$newelement"
        else
            PATH="$newelement:$PATH"
        fi
    fi
}

pathrm() {
    PATH="$(echo $PATH | sed -e "s;\(^\|:\)${1%/}\(:\|\$\);\1\2;g" -e 's;^:\|:$;;g' -e 's;::;:;g')"
}

Mettez-les dans n'importe quel script que vous souhaitez modifier l'environnement PATH et vous pouvez maintenant le faire.

pathadd "/foo/bar"
pathadd "/baz/bat" after
export PATH

Vous êtes assuré de ne pas ajouter au chemin s'il est déjà là. Si vous voulez maintenant vous assurer, /baz/batc'est au début.

pathrm "/baz/bat"
pathadd "/baz/bat"
export PATH

Maintenant, n'importe quel chemin peut être déplacé vers l'avant s'il est déjà dans le chemin sans doubler.

Brett Ryan
la source
Approche connexe et plus propre pour vérifier la présence d’un répertoire dans votre PATH: unix.stackexchange.com/a/32054/135943
Wildcard
9

Je ne peux pas parler pour d'autres distributions, mais Ubuntu a un fichier, / etc / environment, qui est le chemin de recherche par défaut pour tous les utilisateurs. Étant donné que mon ordinateur n’est utilisé que par moi, je mets les répertoires que je veux dans mon chemin, sauf s’il s’agit d’un ajout temporaire que je mets dans un script.

Jim Bradley
la source
6

Il y a des cas où son utilisation PATH=/a/b:$PATHpeut être considérée comme la manière "incorrecte" d'ajouter un chemin à PATH:

  1. Ajout d'un chemin qui n'est pas réellement un répertoire.
  2. Ajouter un chemin qui est déjà PATHdans le même formulaire.
  3. Ajouter un chemin relatif (puisque le répertoire réel recherché changera au fur et à mesure que vous changerez le répertoire de travail actuel).
  4. Ajouter un chemin déjà présent PATHdans un formulaire différent (c.-à-d. Un alias dû à l'utilisation de liens symboliques ou ..).
  5. Si vous évitez de faire 4, ne déplacez pas le chemin au PATHdébut de quand il est destiné à remplacer d'autres entrées dans PATH.

Cette fonction (uniquement pour Bash) fait la "bonne chose" dans les situations ci-dessus (avec une exception, voir ci-dessous), renvoie des codes d'erreur et imprime de gentils messages pour les humains. Les codes d'erreur et les messages peuvent être désactivés lorsqu'ils ne sont pas recherchés.

prepath() {
    local usage="\
Usage: prepath [-f] [-n] [-q] DIR
  -f Force dir to front of path even if already in path
  -n Nonexistent dirs do not return error status
  -q Quiet mode"

    local tofront=false errcode=1 qecho=echo
    while true; do case "$1" in
        -f)     tofront=true;       shift;;
        -n)     errcode=0;          shift;;
        -q)     qecho=':';          shift;;
        *)      break;;
    esac; done
    # Bad params always produce message and error code
    [[ -z $1 ]] && { echo 1>&2 "$usage"; return 1; }

    [[ -d $1 ]] || { $qecho 1>&2 "$1 is not a directory."; return $errcode; }
    dir="$(command cd "$1"; pwd -P)"
    if [[ :$PATH: =~ :$dir: ]]; then
        $tofront || { $qecho 1>&2 "$dir already in path."; return 0; }
        PATH="${PATH#$dir:}"        # remove if at start
        PATH="${PATH%:$dir}"        # remove if at end
        PATH="${PATH//:$dir:/:}"    # remove if in middle
    fi
    PATH="$dir:$PATH"
}

L'exception est que cette fonction ne canonise pas les chemins ajoutés à d' PATHautres moyens. Par conséquent, si un alias non canonique pour un chemin est PATHprésent, un doublon sera ajouté. Essayer de PATHcanoniser des chemins déjà dedans est une proposition risquée puisqu’un chemin relatif a une signification évidente lorsqu’il est passé à, prepathmais quand déjà dans le chemin vous ne savez pas quel était le répertoire de travail actuel au moment de son ajout.

Curt J. Sampson
la source
en ce qui concerne les chemins relatifs: qu’en est-il du commutateur '-r', qui ajouterait le chemin sans le rendre absolu d’abord, et qui le rechercherait également comme absolu avant de l’ajouter? S'il s'agissait d'un script, on pourrait l'utiliser dans d'autres coquilles. Y a-t-il un avantage à l'avoir comme fonction? joli code!
Hoijui
1
@hoijui Il doit s'agir d'une fonction car elle modifie l'environnement actuel. S'il s'agissait d'un script, cela modifierait l'environnement du sous-processus exécutant le script et, à la fin du script, vous auriez le même résultat $PATHque précédemment. Pour ce qui est -r, non, je pense que les chemins relatifs entrés $PATHsont trop peu fiables et étranges (votre chemin change à chaque fois cd!) Pour vouloir prendre en charge quelque chose comme ça dans un outil général.
Curt J. Sampson
5

Pour moi (sous Mac OS X 10.9.5), l’ajout du nom de chemin (par exemple /mypathname) au fichier /etc/pathsa très bien fonctionné.

Avant édition, echo $PATHretourne:

/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin

Après l'édition /etc/pathset le redémarrage du shell, la variable $ PATH est ajoutée /pathname. En effet, echo $PATHretourne:

/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/mypathname

Ce qui est arrivé est que cela /mypathnamea été ajouté à la $PATHvariable.

faelx
la source
3
Mieux vaut ajouter un fichier dans le répertoire /etc/paths.d que de modifier le fichier / etc / path lui-même.
réponse
4

Pour ajouter un nouveau chemin à la PATHvariable d'environnement:

export PATH=$PATH:/new-path/

Pour que cette modification soit appliquée à chaque shell que vous ouvrez, ajoutez-la au fichier que le shell générera lors de son invocation. Dans différentes coquilles, cela peut être:

  • Bash Shell: ~ / .bash_profile, ~ / .bashrc ou profil
  • Korn Shell: ~ / .kshrc ou .profile
  • Shell Z: ~ / .zshrc ou .zprofile

par exemple

# export PATH=$PATH:/root/learning/bin/
# source ~/.bashrc
# echo $PATH

Vous pouvez voir le chemin fourni dans la sortie ci-dessus.

Amit24x7
la source
4

Voici ma solution:

PATH=$(echo -n $PATH | awk -v RS=: -v ORS=: '!x[$0]++' | sed "s/\(.*\).\{1\}/\1/")

Une belle doublure facile qui ne laisse pas de fuite :

UN J.
la source
1
-bash: awk: Aucun fichier ou répertoire de ce type -bash: Sed: Aucun fichier ou répertoire de ce type
davidcondrey
1
@davidcondrey - awk et sed sont des commandes externes très courantes. Cette réponse fournit un moyen purement basque d'obtenir la même chose, donc elle fonctionne même dans les cas où awk et / ou sed ne sont pas présents (ou leurs répertoires respectifs ne sont pas dans le chemin!)
sancho.s le