35 votes

Un moyen plus confortable d'éditer un long $PATH ?

Je veux ajouter, dans ~/.bashrc, quelques répertoires à mon $PATH.

Mon $PATH est assez long et il est un peu difficile de voir quels répertoires il contient et dans quel ordre.

Je sais que je peux modifier mon ~/.bashrc pour être :

PATH=$PATH:/some/dir
PATH=$PATH:/another/dir:/yet/another
PATH=$PATH:/and/another
...

ça serait plus facile à lire. Mais je me demandais si, au cours des dernières années, Bash avait acquis une syntaxe qui facilite la spécification d'un long PATH. Par exemple, je fantasme sur une syntaxe similaire à :

PATH=:((
  /some/dir
  /another/dir
  /yet/another
  /and/another
  ...
))

I connaître une telle syntaxe n'est pas valide. Je me demandais s'il existait quelque chose d'aussi simple. Existe-t-il ?

25voto

Starfish Points 896

J'utilise un ensemble de fonctions pratiques pour ajouter ou ajouter un chemin à une variable. Ces fonctions se trouvent dans la distribution de Bash, dans un fichier contributif appelé "pathfuncs".

  • add_path ajoutera l'entrée à la fin de la variable PATH.
  • pre_path ajoutera l'entrée au début de la variable PATH.
  • del_path supprimera l'entrée de la variable PATH, où qu'elle se trouve.

Si vous spécifiez une variable comme second argument, elle sera utilisée à la place de PATH.

Pour plus de commodité, les voici :

# is $1 missing from $2 (or PATH) ?
no_path() {
    eval "case :\$${2-PATH}: in *:$1:*) return 1;; *) return 0;; esac"
}
# if $1 exists and is not in path, append it
add_path () {
  [ -d ${1:-.} ] && no_path $* && eval ${2:-PATH}="\$${2:-PATH}:$1"
}
# if $1 exists and is not in path, prepend it
pre_path () {
  [ -d ${1:-.} ] && no_path $* && eval ${2:-PATH}="$1:\$${2:-PATH}"
}
# if $1 is in path, remove it
del_path () {
  no_path $* || eval ${2:-PATH}=`eval echo :'$'${2:-PATH}: |
    sed -e "s;:$1:;:;g" -e "s;^:;;" -e "s;:\$;;"`
}

Si vous les ajoutez à votre fichier de démarrage bash, vous pouvez les ajouter à votre PATH comme ceci :

pre_path $HOME/bin
add_path /sbin
add_path /usr/sbin

Ou spécifiez une autre variable :

pre_path $HOME/man MANPATH
pre_path $HOME/share/man MANPATH
add_path /usr/local/man MANPATH
add_path /usr/share/man MANPATH

J'utilise cette méthode dans mes fichiers rc en mettant les pre_paths en premier et les add_paths en second. Cela rend tous mes changements de chemins faciles à comprendre d'un coup d'oeil. Un autre avantage est que les lignes sont suffisamment courtes pour que je puisse ajouter un commentaire à la fin d'une ligne si nécessaire.

Et comme il s'agit de fonctions, vous pouvez les utiliser de manière interactive à partir de la ligne de commande, par exemple en disant add_path $(pwd) pour ajouter le répertoire courant au chemin.

11voto

Niccolo M. Points 734

OK, j'ai trouvé la solution suivante, qui je pense est élégante (en ce qui concerne la syntaxe Shell). Elle utilise la syntaxe des tableaux de Bash ainsi qu'une fonction une manière ordonnée pour joindre des éléments :

paths=(
  /some/dir
  /another/dir
  '/another/dir with spaces in it'
  /yet/another
  /and/another
  /end
)
paths_joined=$( IFS=: ; echo "${paths[*]}" )

PATH=$paths_joined:$PATH

ALERTE !

Il s'avère que cette solution a un problème : Contrairement aux solutions de @terdon et @Starfish, elle ne vérifie pas d'abord si les chemins sont déjà dans PATH. Ainsi, puisque je veux mettre ce code dans ~/.bashrc (et non dans ~/.profile), des chemins en double se glisseront dans PATH. N'utilisez donc pas cette solution (à moins de le mettre dans ~/.profile (ou, mieux, ~/.bash_profile car il a une syntaxe spécifique à Bash)).

5voto

Mohsin Points 11

J'utilise la fonction ci-dessous dans mon ~/.bashrc . C'est quelque chose que j'ai obtenu d'un administrateur système dans mon ancien laboratoire, mais je ne pense pas qu'il les ait écrites. Ajoutez simplement ces lignes à votre ~/.profile o ~/.bashrc :

pathmunge () {
        if ! echo $PATH | /bin/grep -Eq "(^|:)$1($|:)" ; then
           if [ "$2" = "after" ] ; then
              PATH=$PATH:$1
           else
              PATH=$1:$PATH
           fi
        fi
}

Cela présente plusieurs avantages :

  • L'ajout de nouveaux répertoires au $PATH est trivial : pathmunge /foo/bar ;
  • Il permet d'éviter les entrées dupliquées ;
  • Vous pouvez choisir d'ajouter une nouvelle entrée au début ( pathmunge /foo/bar ou la fin ( pathmunge /foo/bar après) de la $PATH .

Le fichier d'initialisation de votre Shell contiendrait alors quelque chose comme :

pathmunge /some/dir
pathmunge /another/dir
pathmunge '/another/dir with spaces in it'
pathmunge /yet/another
pathmunge /and/another
pathmunge /end

4voto

DavidPostill Points 140654

Je veux ajouter, dans ~/.bashrc, quelques répertoires à mon $PATH.

J'utilise ce qui suit dans Cygwin. Cela devrait fonctionner dans d'autres versions de bash. Vous pouvez enlever le unset PATH pour développer votre PATH (si vous faites cela, vous devrez peut-être trouver un moyen d'ajouter l'option : correctement les séparateurs).

Note :

  • J'ai déjà eu cette fonctionnalité dans un bash mais l'a perdue après un crash de disque.

Dans mon .bash_profile :

# Build up the path using the directories in ~/.path_elements
unset PATH
while read line; do 
  PATH="${PATH}$line"; 
done < ~/.path_elements

...

# Add current directory to path
export PATH=".:${PATH}"

Sur ~/.path_elements :

/home/DavidPostill/bin:
/usr/local/bin:
/usr/bin:
/c/Windows/system32:
/c/Windows

1voto

Ramkumar Points 11

Je l'utilise dans mon .bashrc (et aussi dans mon .zshrc, puisque j'utilise généralement zsh quand c'est possible au lieu de bash). Certes, cela me demande d'ajouter manuellement des répertoires, mais l'avantage est qu'au fur et à mesure que je le mets à jour, je peux continuer à le copier sur de nouveaux serveurs et ne pas m'inquiéter que le PATH d'un nouveau serveur soit créé avec des répertoires qui n'y existent pas.

##
## PATH
##
## Instead of just clobbering our PATH with directories that may
## not be appropriate for this server, try to be intelligent about what we add
##
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
\[ -d /cs/sbin \]                  && PATH=/cs/sbin:$PATH
\[ -d /cs/bin \]                   && PATH=/cs/bin:$PATH
\[ -d /usr/ucb \]                  && PATH=$PATH:/usr/ucb
\[ -d /usr/ccs/bin \]              && PATH=$PATH:/usr/ccs/bin
\[ -d /usr/local/ssl/bin \]        && PATH=$PATH:/usr/local/ssl/bin
\[ -d /usr/krb5/bin \]             && PATH=$PATH:/usr/krb5/bin
\[ -d /usr/krb5/sbin \]            && PATH=$PATH:/usr/krb5/sbin
\[ -d /usr/kerberos/sbin \]        && PATH=$PATH:/usr/kerberos/sbin
\[ -d /usr/kerberos/bin \]         && PATH=$PATH:/usr/kerberos/bin
\[ -d /cs/local/jdk1.5.0/bin \]    && PATH=$PATH:/cs/local/jdk1.5.0/bin
\[ -d /usr/java/jre1.5.0\_02/bin \] && PATH=$PATH:/usr/java/jre1.5.0\_02/man
\[ -d /usr/java1.2/bin \]          && PATH=$PATH:/usr/java1.2/bin
\[ -d /cs/local/perl5.8.0/bin \]   && PATH=$PATH:/cs/local/perl5.8.0/bin
\[ -d /usr/perl5/bin \]            && PATH=$PATH:/usr/perl5/bin
\[ -d /usr/X11R6/bin \]            && PATH=$PATH:/usr/X11R6/bin
\[ -d /etc/X11 \]                  && PATH=$PATH:/etc/X11
\[ -d /opt/sfw/bin \]              && PATH=$PATH:/opt/sfw/bin
\[ -d /usr/local/apache/bin \]     && PATH=$PATH:/usr/local/apache/bin
\[ -d /usr/apache/bin \]           && PATH=$PATH:/usr/apache/bin
\[ -d /cs/admin/bin \]             && PATH=$PATH:/cs/admin/bin
\[ -d /usr/openwin/bin \]          && PATH=$PATH:/usr/openwin/bin
\[ -d /usr/xpg4/bin \]             && PATH=$PATH:/usr/xpg4/bin
\[ -d /usr/dt/bin \]               && PATH=$PATH:/usr/dt/bin

Je fais la même chose pour mon MANPATH :

##
## MANPATH
##
## Instead of just clobbering our MANPATH with directories that may
## not be appropriate for this server, try to be intelligent about what we add
##
MANPATH=/usr/local/man
\[ -d /usr/share/man \]            && MANPATH=$MANPATH:/usr/share/man
\[ -d /usr/local/share/man \]      && MANPATH=$MANPATH:/usr/local/share/man
\[ -d /usr/man \]                  && MANPATH=$MANPATH:/usr/man
\[ -d /cs/man \]                   && MANPATH=$MANPATH:/cs/man
\[ -d /usr/krb5/man \]             && MANPATH=$MANPATH:/usr/krb5/man
\[ -d /usr/kerberos/man \]         && MANPATH=$MANPATH:/usr/kerberos/man
\[ -d /usr/local/ssl/man \]        && MANPATH=$MANPATH:/usr/local/ssl/man
\[ -d /cs/local/jdk1.5.0/man \]    && MANPATH=$MANPATH:/cs/local/jdk1.5.0/man
\[ -d /usr/java/jre1.5.0\_02/man \] && MANPATH=$MANPATH:/usr/java/jre1.5.0\_02/man
\[ -d /usr/java1.2/man \]          && MANPATH=$MANPATH:/usr/java1.2/man
\[ -d /usr/X11R6/man \]            && MANPATH=$MANPATH:/usr/X11R6/man
\[ -d /usr/local/apache/man \]     && MANPATH=$MANPATH:/usr/local/apache/man
\[ -d /usr/local/mysql/man \]      && MANPATH=$MANPATH:/usr/local/mysql/man
\[ -d /cs/local/perl5.8.0/man \]   && MANPATH=$MANPATH:/cs/local/perl5.8.0/man
\[ -d /usr/perl5/man \]            && MANPATH=$MANPATH:/usr/perl5/man
\[ -d /usr/local/perl/man \]       && MANPATH=$MANPATH:/usr/local/perl/man
\[ -d /usr/local/perl5.8.0/man \]  && MANPATH=$MANPATH:/usr/local/perl5.8.0/man
\[ -d /usr/openwin/man \]          && MANPATH=$MANPATH:/usr/openwin/man

En plus d'avoir un seul fichier que je peux copier sur des systèmes dans des environnements disparates sans craindre d'ajouter des répertoires inexistants au PATH, cette approche a également l'avantage de me permettre de spécifier l'ordre dans lequel je veux que les répertoires apparaissent dans le PATH. Puisque la première ligne de chaque définition redéfinit complètement la variable PATH, je peux mettre à jour mon .bashrc et le source après l'édition pour que mon Shell soit mis à jour sans ajouter d'entrées en double (ce que j'ai connu il y a longtemps lorsque je commençais simplement par "$PATH=$PATH:/new/dir". Cela me permet d'obtenir une copie propre dans l'ordre que je souhaite.

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X