128 votes

Quelle est la façon la plus élégante pour supprimer un chemin dans la variable $PATH en Bash?

Ou, plus généralement, comment faire pour supprimer un élément à partir d'un colon liste séparée dans un environnement Bash variable?

Je pensais que j'avais vu un moyen simple de le faire il y a des années, à l'aide de la forme plus poussée de Bash extension variable, mais si j'ai perdu la trace. Une recherche rapide sur Google est en place étonnamment peu de résultats pertinents et aucun que je voudrais appeler "simple" ou "élégante". Par exemple, deux méthodes à l'aide de sed et awk, respectivement:

PATH=$(echo $PATH | sed -e 's;:\?/home/user/bin;;' -e 's;/home/user/bin:\?;;')
PATH=!(awk -F: '{for(i=1;i<=NF;i++){if(!($i in a)){a[$i];printf s$i;s=":"}}}'<<<$PATH)

N'a rien de simple, existe t-il? Est-il quelque chose d'analogue à un split() de la fonction en Bash?

Mise à jour:
Il semble que j'ai besoin de m'excuser pour mon intentionnellement vague question; j'étais moins intéressé par la résolution d'un précis de cas d'utilisation que de provoquer la discussion. Heureusement, je l'ai eu!

Il y a quelques très intelligent de techniques, mais il semble qu'il n'y a aucun moyen de le faire à l'aide de la pure script Bash (si nicerobot de l'IFS/tableau technique vient agréablement à proximité). En fin de compte, j'ai ajouté les trois fonctions suivantes de ma boîte à outils. La magie qui se passe dans path_remove, qui est basé en grande partie sur Martin York est une utilisation intelligente de l' awk's variable RS.

path_append ()  { path_remove $1; export PATH="$PATH:$1"; }
path_prepend () { path_remove $1; export PATH="$1:$PATH"; }
path_remove ()  { export PATH=`echo -n $PATH | awk -v RS=: -v ORS=: '$0 != "'$1'"' | sed 's/:$//'`; }

Le seul réel les fichiers inutiles dans l'utilisation de l' sed supprimer la fin du côlon. Compte tenu de la simplicité du reste de Martin solution est bien, je suis tout à fait prêt à vivre avec elle!


Question connexe: http://stackoverflow.com/questions/273909/how-do-i-manipulate-path-elements-in-shell-scripts

63voto

Loki Astari Points 116129

Mon sale hack:

echo ${PATH} > t1
vi t1
export PATH=`cat t1`

58voto

Loki Astari Points 116129

Une minute avec awk:

# Strip all paths with SDE in them.
#
export PATH=`echo ${PATH} | awk -v RS=: -v ORS=: '/SDE/ {next} {print}'`

Edit: la réponse aux observations ci-dessous:

$ export a="/a/b/c/d/e:/a/b/c/d/g/k/i:/a/b/c/d/f:/a/b/c/g:/a/b/c/d/g/i"
$ echo ${a}
/a/b/c/d/e:/a/b/c/d/f:/a/b/c/g:/a/b/c/d/g/i

## Remove multiple (any directory with a: all of them)
$ echo ${a} | awk -v RS=: -v ORS=: '/a/ {next} {print}'
## Works fine all removed

## Remove multiple including last two: (any directory with g)
$ echo ${a} | awk -v RS=: -v ORS=: '/g/ {next} {print}'
/a/b/c/d/e:/a/b/c/d/f:
## Works fine: Again!

Edit en réponse au problème de sécurité: (qui n'est pas pertinent pour la question)

export PATH=`echo ${PATH} | awk -v RS=: -v ORS=: '/SDE/ {next} {print}' | sed 's/:*$//'`

ou:

export PATH=$(echo ${PATH} | awk -v RS=: -v ORS=: '/SDE/ {next} {print}' | sed 's/:*$//')

Il laisse le vide d'un point à la fin. Ce n'est pas une faille de sécurité que rien ne le préfixe du nom de l'application n'aide pas à trouver l'application. Rappelez-vous que le répertoire courant est "./" pas "". Mais là encore, il n'est pas parfait et je devrais avoir dépouillé arrêt (laissé comme exercice au lecteur).

48voto

Andrew Aylett Points 16469

Car le gros problème avec la substitution est la fin des cas, que diriez-vous de prise de la fin des cas, de la même manière pour les autres cas? Si le chemin d'accès déjà eu deux points au début et à la fin, nous pourrions simplement à la recherche pour notre chaîne enveloppé avec des points. Comme il est, nous pouvons facilement ajouter ces deux points et de les supprimer par la suite.

# PATH => /bin:/opt/a dir/bin:/sbin
WORK=:$PATH:
# WORK => :/bin:/opt/a dir/bin:/sbin:
REMOVE='/opt/a dir/bin'
WORK=${WORK/:$REMOVE:/:}
# WORK => :/bin:/sbin:
WORK=${WORK%:}
WORK=${WORK#:}
PATH=$WORK
# PATH => /bin:/sbin

Pur bash :).

27voto

nicerobot Points 4811

Voici la solution la plus simple que je peux concevoir:

#!/bin/bash
IFS=:
# convert it to an array
t=($PATH)
unset IFS
# perform any array operations to remove elements from the array
t=(${t[@]%%*usr*})
IFS=:
# output the new array
echo "${t[*]}"

L'exemple ci-dessus va supprimer n'importe quel élément dans $PATH qui contient "usr". Vous pouvez remplacer "*usr*" par "/home/user/bin" pour supprimer l'élément.

mise à jour par sschuberth

Même si je pense que les espaces dans un $PATH sont une horrible idée, voici une solution qui s'occupe de:

PATH=$(IFS=':';t=($PATH);n=${#t[*]};a=();for ((i=0;i<n;i++)); do p="${t[i]%%*usr*}"; [ "${p}" ] && a[i]="${p}"; done;echo "${a[*]}");

ou

IFS=':'
t=($PATH)
n=${#t[*]}
a=()
for ((i=0;i<n;i++)); do
  p="${t[i]%%*usr*}"
  [ "${p}" ] && a[i]="${p}"
done
echo "${a[*]}"

6voto

Mark Booth Points 2710

Les meilleurs pur bash option que j'ai trouvé jusqu'à présent est la suivante:

function path_remove {
  PATH=${PATH/":$1"/} # delete any instances in the middle or at the end
  PATH=${PATH/"$1:"/} # delete any instances at the beginning
}

Ceci est basé sur les pas assez bonne réponse à Ajouter un répertoire de $PATH si elle n'est pas déjà sur sur de super-Utilisateur.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X