Quelle est la manière la plus élégante de supprimer un chemin de la variable $ PATH dans Bash?

Ou plus généralement, comment supprimer un élément d’une liste séparée par des deux-points dans une variable d’environnement Bash?

Je pensais avoir vu un moyen simple de le faire il y a des années, en utilisant les formes plus avancées d’expansion des variables Bash, mais si c’est le cas, j’en ai perdu la trace. Une recherche rapide sur Google a révélé étonnamment peu de résultats pertinents et aucun que je qualifierais de “simple” ou “élégant”. Par exemple, deux méthodes utilisant respectivement sed et awk:

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) 

Est-ce qu’il n’y a rien de simple? Y at-il quelque chose d’analogue à une fonction split () dans Bash?

Mettre à jour:
Il semble que je doive m’excuser pour ma question intentionnellement vague. J’étais moins intéressé par la résolution d’un cas d’utilisation spécifique que par une bonne discussion. Heureusement, je l’ai eu!

Il y a des techniques très intelligentes ici. Au final, j’ai ajouté les trois fonctions suivantes à ma boîte à outils. La magie se produit dans path_remove, qui repose en grande partie sur l’utilisation intelligente de la variable RS de awk Martin York.

 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/:$//'`; } 

La seule vraie bêtise est l’utilisation de sed pour éliminer les deux points suivants. Compte tenu de la simplicité avec laquelle le rest de la solution de Martin est, je suis tout à fait prêt à vivre avec!


Question connexe: Comment manipuler les éléments $ PATH dans les scripts shell?

Une minute avec awk:

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

Modifier: Il répond aux commentaires 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! 

Modifier en réponse à un problème de sécurité: (qui ne concerne pas la question)

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

Cela supprime tous les deux points de fin en supprimant les dernières entrées, ce qui appendait effectivement . à votre chemin.

Mon sale hack:

 echo ${PATH} > t1 vi t1 export PATH=$(cat t1) 

Étant donné que le problème majeur de la substitution concerne les cas ultimes, pourquoi ne pas faire en sorte que les cas finaux ne soient pas différents des autres cas? Si le chemin avait déjà des deux points au début et à la fin, nous pourrions simplement rechercher la chaîne de caractères souhaitée, entourée de deux points. En fait, nous pouvons facilement append ces deux-points et 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 

Pure bash :).

Voici la solution la plus simple que je puisse imaginer:

 #!/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 supprimera tout élément de $ PATH contenant “usr”. Vous pouvez remplacer “* usr *” par “/ home / user / bin” pour supprimer uniquement cet élément.

mise à jour par sschuberth

Même si je pense que les espaces dans $PATH sont une idée horrible , voici une solution qui le gère:

 PATH=$(IFS=':';t=($PATH);n=${#t[*]};a=();for ((i=0;i 

ou

 IFS=':' t=($PATH) n=${#t[*]} a=() for ((i=0;i 

Voici une page qui, malgré les réponses acceptées et les mieux notées , n’ajoute pas de caractères invisibles à PATH et permet de gérer les chemins contenant des espaces:

 export PATH=$(p=$(echo $PATH | tr ":" "\n" | grep -v "/cygwin/" | tr "\n" ":"); echo ${p%:}) 

Personnellement, je trouve aussi que c’est facile à lire / à comprendre, et cela implique uniquement des commandes communes au lieu d’utiliser awk.

function __path_remove () {
local D = “: $ {PATH}:”;
[“$ {D /: $ 1: /:}”! = “$ D”] && PATH = “$ {D /: $ 1: /:}”;
PATH = “$ {PATH / #: /}”;
exporter PATH = “$ {PATH /%: /}”;
}

Extrayez-le de mon fichier .bashrc. Lorsque vous jouez avec PATH, et qu’il est perdu, awk / sed / grep devient indisponible 🙂

La meilleure option de bash pure que j’ai trouvée 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 la réponse pas tout à fait correcte à Ajouter un répertoire à $ PATH s’il n’est pas déjà fini sur le superutilisateur.

Voici une solution qui:

  • est pur Bash,
  • n’invoque pas d’autres processus (comme ‘sed’ ou ‘awk’),
  • ne change pas IFS ,
  • ne pas bifurquer un sous-shell,
  • gère les chemins avec des espaces, et
  • supprime toutes les occurrences de l’argument dans PATH .

     removeFromPath () {
        pd local
        p = ": $ 1:"
        d = ": $ PATH:"
        d = $ {d // $ p /:}
        d = $ {d / #: /}
        PATH = $ {d /%: /}
     } 

Je viens d’utiliser les fonctions de la dissortingbution bash, qui existent depuis 1991. Elles sont toujours dans le paquet bash-docs sur Fedora, et étaient utilisées dans /etc/profile , mais pas plus …

 $ rpm -ql bash-doc |grep pathfunc /usr/share/doc/bash-4.2.20/examples/functions/pathfuncs $ cat $(!!) cat $(rpm -ql bash-doc |grep pathfunc) #From: "Simon J. Gerraty"  #Message-Id: <199510091130.VAA01188@zen.void.oz.au> #Subject: Re: a shell idea? #Date: Mon, 09 Oct 1995 21:30:20 +1000 # NAME: # add_path.sh - add dir to path # # DESCRIPTION: # These functions originated in /etc/profile and ksh.kshrc, but # are more useful in a separate file. # # SEE ALSO: # /etc/profile # # AUTHOR: # Simon J. Gerraty  # @(#)Copyright (c) 1991 Simon J. Gerraty # # This file is provided in the hope that it will # be of use. There is absolutely NO WARRANTY. # Permission to copy, redissortingbute or otherwise # use this file is hereby granted provided that # the above copyright notice and this notice are # left intact. # 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;:\$;;"` } 

Eh bien, en bash, comme il supporte les expressions régulières, je ferais simplement:

 PATH=${PATH/:\/home\/user\/bin/} 

J’ai écrit une réponse à cela ici (en utilisant awk aussi). Mais je ne suis pas sûr que ce soit ce que vous cherchez? Cela me semble au moins clair, au lieu d’essayer de rentrer dans une seule ligne. Pour un simple paquebot, cependant, cela ne fait que supprimer des choses, je recommande

 echo $PATH | tr ':' '\n' | awk '$0 != "/bin"' | paste -sd: 

Le remplacement est

 echo $PATH | tr ':' '\n' | awk '$0 != "/bin"; $0 == "/bin" { print "/bar" }' | paste -sd: 

ou (plus court mais moins lisible)

 echo $PATH | tr ':' '\n' | awk '$0 == "/bin" { print "/bar"; next } 1' | paste -sd: 

Quoi qu’il en soit, pour la même question et beaucoup de réponses utiles, voir ici .

Oui, par exemple, placer un deux-points à la fin de PATH rend la suppression d’un chemin un peu moins maladroite et sujette à erreur.

 path_remove () { declare i newPATH newPATH="${PATH}:" for ((i=1; i< =${#@}; i++ )); do #echo ${@:${i}:1} newPATH="${newPATH//${@:${i}:1}:/}" done export PATH="${newPATH%:}" return 0; } path_remove_all () { declare i newPATH shopt -s extglob newPATH="${PATH}:" for ((i=1; i<=${#@}; i++ )); do newPATH="${newPATH//+(${@:${i}:1})*([^:]):/}" #newPATH="${newPATH//+(${@:${i}:1})*([^:])+(:)/}" done shopt -u extglob export PATH="${newPATH%:}" return 0 } path_remove /opt/local/bin /usr/local/bin path_remove_all /opt/local /usr/local 

Si vous êtes préoccupé par la suppression des doublons dans $ PATH, la manière la plus élégante, à mon humble avis, serait de ne pas les append en premier lieu. En 1 ligne:

 if ! $( echo "$PATH" | tr ":" "\n" | grep -qx "$folder" ) ; then PATH=$PATH:$folder ; fi 

Le dossier $ peut être remplacé par n’importe quoi et peut contenir des espaces (“/ home / user / mes documents”)

La solution la plus élégante que j’ai trouvée à ce jour:

 pathrm () { local IFS=':' local newpath local dir local pathvar=${2:-PATH} for dir in ${!pathvar} ; do if [ "$dir" != "$1" ] ; then newpath=${newpath:+$newpath:}$dir fi done export $pathvar="$newpath" } pathprepend () { pathrm $1 $2 local pathvar=${2:-PATH} export $pathvar="$1${!pathvar:+:${!pathvar}}" } pathappend () { pathrm $1 $2 local pathvar=${2:-PATH} export $pathvar="${!pathvar:+${!pathvar}:}$1" } 

La plupart des autres solutions suggérées reposent uniquement sur la correspondance de chaînes et ne prennent pas en compte les segments de chemin contenant des noms spéciaux tels que . , .. ou ~ . La fonction bash ci-dessous résout les chaînes de répertoire dans son argument et dans les segments de chemin pour trouver les correspondances de répertoires logiques ainsi que les correspondances de chaînes.

 rm_from_path() { pattern="${1}" dir='' [ -d "${pattern}" ] && dir="$(cd ${pattern} && pwd)" # resolve to absolute path new_path='' IFS0=${IFS} IFS=':' for segment in ${PATH}; do if [[ ${segment} == ${pattern} ]]; then # ssortingng match continue elif [[ -n ${dir} && -d ${segment} ]]; then segment="$(cd ${segment} && pwd)" # resolve to absolute path if [[ ${segment} == ${dir} ]]; then # logical directory match continue fi fi new_path="${new_path}${IFS}${segment}" done new_path="${new_path/#${IFS}/}" # remove leading colon, if any IFS=${IFS0} export PATH=${new_path} } 

Tester:

 $ mkdir -p ~/foo/bar/baz ~/foo/bar/bif ~/foo/boo/bang $ PATH0=${PATH} $ PATH=~/foo/bar/baz/.././../boo/././../bar:${PATH} # add dir with special names $ rm_from_path ~/foo/boo/../bar/. # remove same dir with different special names $ [ ${PATH} == ${PATH0} ] && echo 'PASS' || echo 'FAIL' 

J’aime les trois fonctions présentées dans la mise à jour de @ BenBlank à sa question initiale. Pour les généraliser, j’utilise un formulaire à 2 arguments, ce qui me permet de définir PATH ou toute autre variable d’environnement souhaitée:

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

Exemples d’utilisation:

 path_prepend PATH /usr/local/bin path_append PERL5LIB "$DEVELOPMENT_HOME/p5/src/perlmods" 

Notez que j’ai également ajouté des guillemets pour permettre le traitement correct des chemins d’access contenant des espaces.

Quelle est la manière la plus élégante de supprimer un chemin de la variable $ PATH dans Bash?

Quoi de plus élégant que awk?

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

Python! C’est une solution plus lisible et maintenable, et il est facile de l’inspecter pour voir qu’elle fait vraiment ce que vous voulez.

Disons que vous voulez supprimer le premier élément de chemin?

 PATH="$(echo "$PATH" | python -c "import sys; path = sys.stdin.read().split(':'); del path[0]; print(':'.join(path))")" 

(Au lieu de os.getenv['PATH'] echo , os.getenv['PATH'] serait un peu plus court, et donnerait le même résultat que ci-dessus, mais je crains que Python ne fasse quelque chose avec cette variable d’environnement, le canaliser directement de l’environnement qui vous intéresse.)

De même pour supprimer de la fin:

 PATH="$(echo "$PATH" | python -c "import sys; path = sys.stdin.read().split(':'); del path[-1]; print(':'.join(path))")" 

Pour créer ces fonctions shell réutilisables, vous pouvez, par exemple, coller dans votre fichier .bashrc:

 ssortingp_path_first () { PATH="$(echo "$PATH" | python -c "import sys; path = sys.stdin.read().split(':'); del path[0]; print(':'.join(path))")" } ssortingp_path_last () { PATH="$(echo "$PATH" | python -c "import sys; path = sys.stdin.read().split(':'); del path[-1]; print(':'.join(path))")" } 

Étant donné que cela a tendance à être assez problématique, comme il n’y a AUCUNE manière élégante, je recommande d’éviter le problème en réorganisant la solution: construisez votre PATH plutôt que d’essayer de le détruire.

Je pourrais être plus précis si je connaissais votre véritable contexte de problème. Dans l’intervalle, j’utiliserai une version de logiciel comme contexte.

Un problème commun avec les versions de logiciel est qu’il se brise sur certaines machines, en raison de la façon dont quelqu’un a configuré son shell par défaut (PATH et d’autres variables d’environnement). La solution élégante consiste à rendre vos scripts de construction immunisés en spécifiant complètement l’environnement du shell. Codez vos scripts de génération pour définir PATH et d’autres variables d’environnement en fonction de l’assemblage d’éléments contrôlés, tels que l’emplacement du compilateur, des bibliothèques, des outils, des composants, etc. puis utilisez de manière appropriée dans votre script.

Par exemple, j’ai une version Java ciblée par WebLogic basée sur Maven, dont j’ai hérité chez mon nouvel employeur. Le script de construction est connu pour être fragile, et un autre nouvel employé et moi avons passé trois semaines (pas à temps plein, juste ici et là, mais encore plusieurs heures) à le faire fonctionner sur nos machines. Une étape essentielle était que je prenais le contrôle du PATH pour que je sache exactement quel Java, quel Maven et quel WebLogic étaient invoqués. J’ai créé des variables d’environnement pour désigner chacun de ces outils, puis j’ai calculé le PATH en fonction de ceux-ci et de quelques autres. Des techniques similaires apprivoisaient les autres parameters configurables, jusqu’à ce que nous ayons finalement créé une version reproductible.

Au fait, n’utilisez pas Maven, Java est correct, et n’achetez WebLogic que si vous avez absolument besoin de son clustering (mais autrement non, et surtout pas ses fonctionnalités propriétaires).

Meilleurs vœux.

Comme avec @litb, j’ai apporté une réponse à la question ” Comment manipuler les éléments $ PATH dans les scripts shell “, ma principale réponse est donc la suivante.

La fonctionnalité «split» dans bash et les autres dérivés du shell Bourne est parfaitement obtenue avec $IFS , le séparateur inter-champs. Par exemple, pour définir les arguments de position ( $1 , $2 , …) sur les éléments de PATH, utilisez:

 set -- $(IFS=":"; echo "$PATH") 

Cela fonctionnera correctement tant qu’il n’y aura pas d’espace dans $ PATH. Le faire fonctionner pour les éléments de chemin contenant des espaces est un exercice non sortingvial – laissé au lecteur intéressé. Il est probablement plus simple de l’utiliser avec un langage de script tel que Perl.

J’ai aussi un script, clnpath , que j’utilise beaucoup pour configurer mon PATH. Je l’ai documenté dans la réponse à ” Comment éviter de dupliquer la variable PATH dans csh “.

Ce qui rend ce problème ennuyeux, ce sont les cas de clôture parmi les premiers et les derniers éléments. Le problème peut être résolu de manière élégante en changeant IFS et en utilisant un tableau, mais je ne sais pas comment réintroduire les deux points une fois que le chemin est converti en tableau.

Voici une version légèrement moins élégante qui supprime un répertoire de $PATH utilisant uniquement la manipulation de chaînes. Je l’ai testé

 #!/bin/bash # # remove_from_path dirname # # removes $1 from user's $PATH if [ $# -ne 1 ]; then echo "Usage: $0 pathname" 1>&2; exit 1; fi delendum="$1" NEWPATH= xxx="$IFS" IFS=":" for i in $PATH ; do IFS="$xxx" case "$i" in "$delendum") ;; # do nothing *) [ -z "$NEWPATH" ] && NEWPATH="$i" || NEWPATH="$NEWPATH:$i" ;; esac done PATH="$NEWPATH" echo "$PATH" 

Voici un one-liner de Perl:

 PATH=`perl -e '$a=shift;$_=$ENV{PATH};s#:$a(:)|^$a:|:$a$#$1#;print' /home/usr/bin` 

La variable $a obtient le chemin à supprimer. Les commandes s (substitut) et print agissent implicitement sur la variable $_ .

De bonnes choses ici. J’utilise celui-ci pour ne pas append de dupes en premier lieu.

 #!/bin/bash # ###################################################################################### # # Allows a list of additions to PATH with no dupes # # Patch code below into your $HOME/.bashrc file or where it # will be seen at login. # # Can also be made executable and run as-is. # ###################################################################################### # add2path=($HOME/bin .) ## uncomment space separated list if [ $add2path ]; then ## skip if list empty or commented out for nodup in ${add2path[*]} do case $PATH in ## case block thanks to MIKE511 $nodup:* | *:$nodup:* | *:$nodup ) ;; ## if found, do nothing *) PATH=$PATH:$nodup ## else, add it to end of PATH or esac ## *) PATH=$nodup:$PATH prepend to front done export PATH fi ## debug add2path echo echo " PATH == $PATH" echo 

Avec la globalisation étendue activée, il est possible de faire ce qui suit:

 # delete all /opt/local paths in PATH shopt -s extglob printf "%s\n" "${PATH}" | tr ':' '\n' | nl printf "%s\n" "${PATH//+(\/opt\/local\/)+([^:])?(:)/}" | tr ':' '\n' | nl man bash | less -p extglob 

One-liner globbing étendu (bien, sorte de):

 path_remove () { shopt -s extglob; PATH="${PATH//+(${1})+([^:])?(:)/}"; export PATH="${PATH%:}"; shopt -u extglob; return 0; } 

Il ne semble pas nécessaire d’échapper à des barres obliques dans $ 1.

 path_remove () { shopt -s extglob; declare escArg="${1//\//\\/}"; PATH="${PATH//+(${escArg})+([^:])?(:)/}"; export PATH="${PATH%:}"; shopt -u extglob; return 0; } 

Ajouter des deux-points à PATH pourrait aussi faire quelque chose comme:

 path_remove () { declare i newPATH # put a colon at the beginning & end AND double each colon in-between newPATH=":${PATH//:/::}:" for ((i=1; i< =${#@}; i++)); do #echo ${@:${i}:1} newPATH="${newPATH//:${@:${i}:1}:/}" # s/:\/fullpath://g done newPATH="${newPATH//::/:}" newPATH="${newPATH#:}" # remove leading colon newPATH="${newPATH%:}" # remove trailing colon unset PATH PATH="${newPATH}" export PATH return 0 } path_remove_all () { declare i newPATH extglobVar extglobVar=0 # enable extended globbing if necessary [[ ! $(shopt -q extglob) ]] && { shopt -s extglob; extglobVar=1; } newPATH=":${PATH}:" for ((i=1; i<=${#@}; i++ )); do newPATH="${newPATH//:+(${@:${i}:1})*([^:])/}" # s/:\/path[^:]*//g done newPATH="${newPATH#:}" # remove leading colon newPATH="${newPATH%:}" # remove trailing colon # disable extended globbing if it was enabled in this function [[ $extglobVar -eq 1 ]] && shopt -u extglob unset PATH PATH="${newPATH}" export PATH return 0 } path_remove /opt/local/bin /usr/local/bin path_remove_all /opt/local /usr/local 

Dans path_remove_all (par proxxy):

 -newPATH="${newPATH//:+(${@:${i}:1})*([^:])/}" +newPATH="${newPATH//:${@:${i}:1}*([^:])/}" # s/:\/path[^:]*//g 

Bien que ce soit un très vieux sujet, je pensais que cette solution pouvait être intéressante:

 PATH="/usr/lib/ccache:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games" REMOVE="ccache" # whole or part of a path :) export PATH=$(IFS=':';p=($PATH);unset IFS;p=(${p[@]%%$REMOVE});IFS=':';echo "${p[*]}";unset IFS) echo $PATH # outputs /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games 

l’a trouvé sur cet article de blog . Je pense que je l’aime le plus 🙂

J’ai adopté une approche légèrement différente de la plupart des gens ici et je me suis concentré spécifiquement sur la manipulation des cordes, comme ceci:

 path_remove () { if [[ ":$PATH:" == *":$1:"* ]]; then local dirs=":$PATH:" dirs=${dirs/:$1:/:} export PATH="$(__path_clean $dirs)" fi } __path_clean () { local dirs=${1%?} echo ${dirs#?} } 

Ce qui précède est un exemple simplifié des fonctions finales que j’utilise. J’ai également créé path_add_before et path_add_after vous permettant d’insérer un chemin avant / après un chemin spécifié dans PATH.

L’ensemble complet des fonctions est disponible dans path_helpers.sh dans mes fichiers dot . Ils prennent entièrement en charge la suppression / ajout / ajout / insertion au début / au milieu / à la fin de la chaîne PATH.

Le «:» final est dû au fait que vous définissez la fin de ligne, pas le séparateur. J’utilise des unités limitées par les ressources et j’aime tout emballer dans un seul script, sans ces bizarreries:

 path_remove () { PATH="$(echo -n $PATH | awk -v RS=: -v ORS= '$0 != "'$1'"{print s _ $0;s=":"}')" } 

Ceci est certainement élégant, mais il utilise le sed externe. De plus, il supprime tous les chemins contenant la chaîne de recherche $ 1. Il ne laisse pas non plus de trace: à la fin, si le chemin supprimé est le dernier sur le PATH.

 PATH=`echo $PATH | sed 's/:[^:]*$1[^:]*//g'` 

Cette alternative laisse une finale en suspens: cependant.

 PATH=`echo $PATH | tr ":" "\n" | grep -v $1 | tr "\n" ":"` 

Les alternatives sans backticks sont:

 PATH=$(echo $PATH | sed 's/:[^:]*$1[^:]*//g') PATH=$(echo $PATH | tr ":" "\n" | grep -v $1 | tr "\n" ":")