web-dev-qa-db-fra.com

Comment ajouter correctement un chemin vers PATH?

Je me demande où un nouveau chemin doit être ajouté à la variable d'environnement PATH. Je sais que cela peut être accompli en modifiant .bashrc (par exemple), mais la procédure à suivre n'est pas claire.

Par ici:

export PATH=~/opt/bin:$PATH

ou ca?

export PATH=$PATH:~/opt/bin
994
Paolo

Les trucs simples

PATH=$PATH:~/opt/bin

ou

PATH=~/opt/bin:$PATH

selon que vous souhaitez 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/bin ou des variations sur la commande fonctionnent très bien. Ne mettez pas export au début de la ligne car cela présente des complications supplémentaires (voir ci-dessous sous "Notes sur les shells autres que bash").

Si votre PATH est construit par de nombreux composants différents, vous pourriez vous retrouver avec des entrées en double. Voir Comment ajouter le chemin du répertoire personnel à découvrir par Unix quelle commande? et Supprimer les entrées $ PATH en double avec la commande awk pour éviter d'ajouter des doublons ou de les supprimer.

Certaines distributions mettent automatiquement ~/bin dans votre CHEMIN s'il existe, soit dit en passant.

Où le mettre

Mettez la ligne pour modifier PATH dans ~/.profile, ou dans ~/.bash_profile si c'est ce que vous avez.

Notez que ~/.bash_rc n'est lu par aucun programme et ~/.bashrc est le 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 des variables d'environnement telles que PATH est ~/.profile (ou ~/.bash_profile si vous ne vous souciez pas des obus autres que bash). Voir Quelle est la différence entre eux et lequel dois-je utiliser?

Ne le mettez pas dans /etc/environment ou ~/.pam_environment: ce ne sont pas des fichiers Shell, vous ne pouvez pas utiliser de substitutions comme $PATH là-dedans. Dans ces fichiers, vous pouvez uniquement remplacer une variable, pas y ajouter.

Complications potentielles dans certains scripts système

Vous n'avez pas besoin de export si la variable est déjà dans l'environnement: tout changement de la valeur de la variable se reflète dans l'environnement.¹ PATH est à peu près toujours dans l'environnement; tous les systèmes Unix le définissent très tôt (généralement dans le tout premier processus, en fait).

Au moment de la connexion, vous pouvez compter sur PATH étant déjà dans l'environnement et contenant déjà certains répertoires système. Si vous écrivez un script qui peut être exécuté tôt lors de la configuration d'une sorte d'environnement virtuel, vous devrez peut-être vous assurer que PATH n'est pas vide et exporté: si PATH n'est toujours pas défini , puis quelque chose comme PATH=$PATH:/some/directory définirait PATH sur :/some/directory, et le composant vide au début signifie le répertoire courant (comme .:/some/directory).

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

Notes sur les coquilles autres que bash

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

Donc, dans des coquilles comme un tiret, export PATH=~/opt/bin:$PATH définit PATH sur la chaîne littérale ~/opt/bin/: suivi de la valeur de PATH jusqu'au premier espace. PATH=~/opt/bin:$PATH (une simple tâche) ne nécessite pas de guillemets et fait la bonne chose. Si vous souhaitez utiliser export dans 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 PATH pour la portabilité, même pour le Bourne Shell qui n'a pas accepté export var=value et n'a pas fait d'extension tilde).

¹ Ce n'était pas vrai dans les coquilles Bourne (comme dans la coquille Bourne réelle, pas les coquilles modernes de style POSIX), mais il est très peu probable que vous rencontriez de tels coquillages de nos jours.

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

En particulier, d'un point de vue de la sécurité, il est dangereux d'ajouter des chemins vers l'avant, car si quelqu'un peut accéder en écriture à votre ~/opt/bin, ils peuvent y mettre, par exemple, un ls différent, que vous utiliserez alors probablement au lieu de /bin/ls sans s'en apercevoir. Imaginez maintenant la même chose pour ssh ou votre navigateur ou choix ... (La même chose vaut trois fois pour mettre. Dans votre chemin.)

88
Ulrich Schwarz

Je suis confus par la question 2 (retirée de la question car elle était due à un problème sans rapport):

Quelle est une façon pratique d'ajouter plus de chemins sur différentes lignes? Au début, je pensais 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 n'ajoute pas seulement ~/opt/node/bin, mais aussi l'ensemble PATH précédemment attribué.

Il s'agit d'une solution de contournement possible:

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

mais pour plus de lisibilité, je préfère avoir une affectation pour un chemin.

Si tu le dis

PATH=~/opt/bin

c'est tout qui sera dans votre CHEMIN. PATH est juste une variable d'environnement, et si vous voulez ajouter au 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 est exactement ce que vous voulez faire, à moins que je manque totalement le point de la question.

J'utilise les deux formulaires dans mon code. J'ai un profil générique que j'installe sur chaque machine sur laquelle je travaille qui ressemble à ceci, pour s'adapter aux 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
39
Carl Cravens

Linux détermine le chemin de recherche exécutable avec le $PATH variable d'environnement. Pour ajouter le répertoire/data/myscripts au début du $PATH variable 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édents ne sont pas suffisants car lorsque vous définissez une variable d'environnement dans un script, cette modification n'est effective que dans le script. Il n'y a que deux façons 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, toutes les modifications d'environnement dans le script sont effectives dans le programme appelant. Une telle inclusion peut être effectuée 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 en C. Donc c'est efficace à l'intérieur du script ou du programme "appelant". Mais bien sûr, il 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ètre de la variable d'environnement avec une commande d'exportation.

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

PATH=$PATH:/data/myscripts
export PATH

place efficacement ces 2 lignes de code dans le programme bash. Donc, dans bash, la variable $ PATH inclut $HOME/myscript.sh, et en raison de l'instruction d'exportation, tous les programmes appelés par bash ont la modification $PATH variable. Et comme tous les programmes que vous exécutez à partir d'une invite bash sont appelés par bash, le nouveau chemin est en vigueur pour tout ce que vous exécutez à partir de l'invite bash.

L'essentiel est que pour ajouter un nouveau répertoire au chemin, vous devez ajouter ou ajouter le répertoire à la variable d'environnement $ PATH dans un script inclus dans le shell, et vous devez exporter le $PATH variable d'environnement.

Plus d'informations ici

25
Steve Brown

Depuis quelque temps, je garde avec moi deux fonctions pathadd et pathrm qui aident à ajouter des éléments au chemin sans avoir à se soucier des doublons.

pathadd prend un seul argument de chemin et un argument facultatif after qui, s'il est fourni, s'ajoutera au PATH sinon il le rajoutera.

Dans presque toutes les situations, si vous ajoutez au chemin, vous souhaiterez probablement remplacer tout ce qui se trouve déjà dans le chemin, c'est pourquoi j'opte pour le préfixe 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 que /baz/bat 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.

20
Brett Ryan

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, j'y place tous les répertoires que je souhaite, sauf s'il s'agit d'un ajout temporaire que je mets dans un script.

10
Jim Bradley

Il y a des situations où il utilise PATH=/a/b:$PATH pourrait être considéré comme la manière "incorrecte" d'ajouter un chemin d'accès à PATH:

  1. Ajout d'un chemin qui n'est pas réellement un répertoire.
  2. Ajout d'un chemin déjà dans PATH dans le même formulaire.
  3. Ajout d'un chemin relatif (puisque le répertoire réel recherché changerait à mesure que vous changez le répertoire de travail actuel).
  4. Ajout d'un chemin qui est déjà dans PATH sous une forme différente (c'est-à-dire un alias dû à l'utilisation de liens symboliques ou ..).
  5. Si vous évitez de faire 4, ne déplacez pas le chemin à l'avant de PATH quand il est destiné à remplacer les autres entrées dans PATH.

Cette fonction (Bash uniquement) fait la "bonne chose" dans les situations ci-dessus (à une exception près, voir ci-dessous), renvoie des codes d'erreur et imprime de beaux messages pour les humains. Les codes d'erreur et les messages peuvent être désactivés lorsqu'ils ne sont pas souhaité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 à PATH par d'autres moyens, donc si un alias non canonique pour un chemin est dans PATH, cela ajoutera un doublon. Essayer de canoniser des chemins déjà dans PATH est une proposition risquée car un chemin relatif a une signification évidente lorsqu'il est passé à prepath mais quand il est déjà dans le chemin, vous ne savez pas quel était le répertoire de travail actuel. quand il a été ajouté.

7
cjs

Pour ajouter un nouveau chemin à la variable d'environnement PATH:

export PATH=$PATH:/new-path/

Pour que cette modification soit appliquée à chaque shell que vous ouvrez, ajoutez-le au fichier que le shell source lors de son appel. 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 d'accès fourni dans la sortie ci-dessus.

7
Amit24x7

Pour moi (sur Mac OS X 10.9.5), ajouter le nom du chemin (par exemple /mypathname) dans le fichier /etc/paths a très bien fonctionné.

Avant la modification, echo $PATH Retour:

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

Après avoir édité /etc/paths et en redémarrant le Shell, la variable $ PATH est ajoutée avec /pathname. En effet, echo $PATH Retour:

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

Ce qui s'est passé, c'est que /mypathname a été ajouté à la $PATH variable.

6
faelx

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 :

5
AJ.