Quelle est la manière la plus élégante de supprimer un chemin de la variable $ PATH dans Bash?
-
21-08-2019 - |
Question
Ou plus généralement, comment puis-je supprimer un élément d'une liste séparée-virgule dans une variable d'environnement Bash?
Je pensais avoir vu un moyen simple de faire il y a des années, en utilisant les formes plus avancées d'expansion variables Bash, mais si j'ai donc perdu la trace. Une recherche rapide de Google se étonnamment peu de résultats pertinents et que je ne qualifierais « simple » ou « élégant ». Par exemple, deux méthodes utilisant 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)
Ne EXISTE rien simple? Y at-il quelque chose d'analogue à une fonction split () dans Bash?
Mise à jour: On dirait que je dois présenter mes excuses pour ma question intentionnellement vague; Je suis moins intéressé par la résolution d'un cas d'utilisation spécifique que à provoquer une bonne discussion. Heureusement, je l'ai!
Il y a quelques ici des techniques très intelligentes. En fin de compte, je l'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 Martin York variable RS de awk
.
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 cochonneries là est l'utilisation de pour enlever le sed
deux points de fuite. Considérant la façon simple le reste de la solution de Martin est, bien, je suis prêt à vivre avec elle!
question connexe: How-je manipuler $ PATH éléments dans les scripts shell
La solution
Une minute avec awk:
# Strip all paths with SDE in them.
#
export PATH=`echo ${PATH} | awk -v RS=: -v ORS=: '/SDE/ {next} {print}'`
Edit: Il réponse 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é: (ce n'est pas pertinente à la question)
export PATH=$(echo ${PATH} | awk -v RS=: -v ORS=: '/SDE/ {next} {print}' | sed 's/:*$//')
Cela supprime toutes les deux points de suivi gauche en supprimant les dernières entrées, ce qui ajouterait effectivement à votre chemin .
.
Autres conseils
Mon bidouille:
echo ${PATH} > t1
vi t1
export PATH=$(cat t1)
Depuis le gros problème avec la substitution est le cas de fin, que diriez-vous faire les affaires de fin ne différentes aux autres cas? Si le chemin avait déjà au début côlons et à la fin, nous pourrions simplement chercher notre chaîne désirée enveloppé avec deux points. Comme il est, nous pouvons facilement ajouter ces deux points et les enlever 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
bash pur.)
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 effacera tout élément dans $ PATH qui contient « usr ». Vous pouvez remplacer "* usr *" avec "/ home / user / bin" pour supprimer tout cet élément.
mise à jour par sschuberth
Même si je pense que les espaces dans un sont un $PATH
horribles idée, voici une solution qu'il gère:
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[*]}"
Voici une seule ligne qui, malgré le courant accepté et réponses les mieux notées, ne pas ajouter des caractères invisibles à PATH et peuvent faire face à des chemins contenant des espaces:
export PATH=$(p=$(echo $PATH | tr ":" "\n" | grep -v "/cygwin/" | tr "\n" ":"); echo ${p%:})
Personnellement, je trouve aussi ce facile à lire / comprendre, et il ne porte que sur les commandes communes au lieu d'utiliser awk.
Voici une solution:
- est Bash pur,
- ne pas invoquer d'autres processus (comme 'sed' ou 'awk'),
- ne change pas
IFS
, - ne fourche pas un sous-shell,
- gère les chemins avec des espaces et
-
supprime toutes les occurrences de l'argument en
PATH
.removeFromPath() { local p d p=":$1:" d=":$PATH:" d=${d//$p/:} d=${d/#:/} PATH=${d/%:/} }
fonction __path_remove () {
D = local ": $ {PATH}:";
[ "$ {D /: 1 $: /:}" = "$ D"!] && PATH = "$ {D /: 1 $: /:}";
PATH = "$ {PATH / #: /}";
export PATH = "$ {PATH /%: /}";
}
Dug dehors de mon .bashrc. Lorsque vous jouez avec PATH, et il se perd, awk / sed / grep devient indisponible: -)
La meilleure option bash pur que j'ai trouvé à ce jour est le suivant:
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 le pas de réponse tout à fait correcte Ajouter un répertoire au PATH $ si elle est pas déjà sur le super-utilisateur.
Je viens en utilisant les fonctions de la distribution de bash, qui ont été là apparemment depuis 1991. Ce sont encore dans le paquet bash-docs sur Fedora, et utilisé pour être utilisé 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" <sjg@zen.void.oz.au>
#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 <sjg@zen.void.oz.au>
# @(#)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, redistribute 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;:\$;;"`
}
J'ai écrit une réponse à cette ici (en utilisant awk aussi). Mais je ne suis pas sûr que ce que vous cherchez? Il semble au moins clair pour moi ce qu'il fait, au lieu d'essayer d'entrer dans une ligne. Pour une simple doublure, cependant, qui ne supprime que 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 et 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 .
Eh bien, en bash, comme il soutient l'expression régulière, je voudrais simplement faire:
PATH=${PATH/:\/home\/user\/bin/}
Quelle est la manière la plus élégante de supprimer un chemin de la variable $ PATH dans Bash?
Ce qui est plus élégant que awk?
path_remove () { export PATH=`echo -n $PATH | awk -v RS=: -v ORS=: '$0 != "'$1'"' | sed 's/:$//'`;
Python! Il est une solution plus lisible et maintenable, et il est facile d'inspecter les lieux pour que ça fait vraiment ce que vous voulez.
Dites 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 la tuyauterie de echo
, serait un os.getenv['PATH']
peu plus court, et à condition que le même résultat que ci-dessus, mais je suis inquiet que Python pourrait faire quelque chose avec cette variable d'environnement, il est donc probablement préférable de tuyau directement à partir de l'environnement que vous aimez.)
De la même façon à supprimer de la fin:
PATH="$(echo "$PATH" | python -c "import sys; path = sys.stdin.read().split(':'); del path[-1]; print(':'.join(path))")"
Pour ces fonctions shell réutilisables que vous pouvez, par exemple, coller dans votre fichier .bashrc:
strip_path_first () {
PATH="$(echo "$PATH" |
python -c "import sys; path = sys.stdin.read().split(':'); del path[0]; print(':'.join(path))")"
}
strip_path_last () {
PATH="$(echo "$PATH" |
python -c "import sys; path = sys.stdin.read().split(':'); del path[-1]; print(':'.join(path))")"
}
Oui, mettre deux points à la fin de PATH, par exemple, permet la suppression d'un chemin
un peu moins maladroit et sujette aux erreurs.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 façon la plus élégante, à mon humble avis, serait de ne pas les ajouter en premier lieu. Dans une ligne:
if ! $( echo "$PATH" | tr ":" "\n" | grep -qx "$folder" ) ; then PATH=$PATH:$folder ; fi
dossier $ peut être remplacé par quoi que ce soit, et peut contenir des espaces ( "/ home / user / mes documents")
La solution la plus élégante bash pur que j'ai trouvé à 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 proposées reposent uniquement sur la correspondance de chaîne et ne prennent pas en compte les segments de chemin contenant des noms spéciaux comme .
, ..
ou ~
. La fonction bash ci-dessous résout les chaînes de répertoire dans son argumentation et dans les segments de chemin pour trouver le répertoire logique correspond ainsi que les correspondances.
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 # string 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}
}
Test:
$ 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'
Linux à partir de zéro définit trois fonctions bash /etc/profile
:
# Functions to help us manage paths. Second argument is the name of the
# path variable to be modified (default: PATH)
pathremove () {
local IFS=':'
local NEWPATH
local DIR
local PATHVARIABLE=${2:-PATH}
for DIR in ${!PATHVARIABLE} ; do
if [ "$DIR" != "$1" ] ; then
NEWPATH=${NEWPATH:+$NEWPATH:}$DIR
fi
done
export $PATHVARIABLE="$NEWPATH"
}
pathprepend () {
pathremove $1 $2
local PATHVARIABLE=${2:-PATH}
export $PATHVARIABLE="$1${!PATHVARIABLE:+:${!PATHVARIABLE}}"
}
pathappend () {
pathremove $1 $2
local PATHVARIABLE=${2:-PATH}
export $PATHVARIABLE="${!PATHVARIABLE:+${!PATHVARIABLE}:}$1"
}
export -f pathremove pathprepend pathappend
Ref: http://www.linuxfromscratch.org/blfs/ vue / svn / postlfs / profile.html
J'aime les trois fonctions indiquées dans @ la mise à jour de BenBlank à sa question initiale. Pour les généraliser, j'utiliser un formulaire 2 argument, ce qui me permet de définir PATH ou toute autre variable d'environnement que je veux:
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 aussi ajouté quelques guillemets pour permettre le traitement approprié des espaces contenant des noms de fichiers.
Depuis cela tend à être très problématique, comme il n'y a pas de façon élégante, je vous recommande d'éviter le problème en réorganisant la solution. Construire votre PATH plutôt que de tenter de le détruire
Je pourrais être plus précis si je savais que votre contexte réel problème. Dans l'intervalle, je vais utiliser une version du logiciel est le contexte.
Un problème commun avec le logiciel construit est qu'il casse sur certaines machines, en fin de compte en raison de la façon dont quelqu'un a configuré sa shell par défaut (PATH et d'autres variables d'environnement). La solution élégante est de rendre vos scripts construire immunitaire en spécifiant complètement l'environnement du shell. Code vos scripts de compilation pour définir le chemin et d'autres variables d'environnement basé sur l'assemblage des pièces que vous contrôlez, comme l'emplacement du compilateur, des bibliothèques, des outils, des composants, etc. Chaque élément doit être configuré quelque chose que vous pouvez définir individuellement, vérifiez et puis utiliser de façon appropriée dans votre script.
Par exemple, j'ai une version Java WebLogic ciblée basée sur Maven que j'ai hérité de mon nouvel employeur. Le script de construction est connu pour être fragile, et un autre nouvel employé et j'ai passé trois semaines (temps plein, juste ici et là, mais encore beaucoup d'heures) le faire fonctionner sur nos machines. Une étape essentielle est que je pris le contrôle du chemin afin que je savais exactement où Java, Maven, et qui WebLogic a été invoquée. J'ai créé des variables d'environnement pour pointer vers chacun de ces outils, je calcule le PATH basé sur les plus quelques autres. Des techniques similaires domptés les autres paramètres configurables, jusqu'à ce que nous a finalement créé une version reproductible.
Par ailleurs, ne pas utiliser Maven, Java est correct, et seulement acheter WebLogic si vous avez absolument besoin de son regroupement (mais sinon pas, et surtout pas ses caractéristiques exclusives).
Les meilleurs voeux.
Comme @litb, je contribuais une réponse à la question " Comment garder de duplication variable PATH csh ».
Ce qui rend ce problème ennuyeux sont les cas de fencepost entre premier et dernier éléments. Le problème peut être résolu avec élégance en changeant IFS et en utilisant un tableau, mais je ne sais pas comment réintroduire le côlon une fois que le chemin est converti sous forme de tableau.
Voici une version légèrement moins élégante qui supprime un répertoire de manipulation en utilisant uniquement $PATH
de chaîne. 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 Perl one-liner:
PATH=`perl -e '$a=shift;$_=$ENV{PATH};s#:$a(:)|^$a:|:$a$#$1#;print' /home/usr/bin`
La variable obtient le chemin $a
à enlever. Le s
(suppléant) et print
commandes opèrent implicitement sur la variable $_
.
Une bonne adresse ici. Je l'utilise celui-ci pour ne pas ajouter 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 jokers permis 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
Extended englobement d'un revêtement (ainsi, en quelque sorte):
path_remove () { shopt -s extglob; PATH="${PATH//+(${1})+([^:])?(:)/}"; export PATH="${PATH%:}"; shopt -u extglob; return 0; }
Il ne semble pas nécessaire d'échapper à barres obliques dans 1 $.
path_remove () { shopt -s extglob; declare escArg="${1//\//\\/}"; PATH="${PATH//+(${escArg})+([^:])?(:)/}"; export PATH="${PATH%:}"; shopt -u extglob; return 0; }
Ajout de chemin que nous côlons pourrions 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 fil très vieux, je pensais que cette solution pourrait être d'intérêt:
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
Je pris une approche légèrement différente que la plupart des gens ici et concentrais spécifiquement sur seulement la manipulation de chaînes, comme suit:
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 aussi créé et path_add_before
vous permettant d'insérer path_add_after
un chemin avant / après un chemin d'accès spécifié déjà PATH.
L'ensemble des fonctions disponibles dans path_helpers.sh dans mon dotfiles . Ils soutiennent pleinement la suppression / appending / appending / insertion au début / milieu / fin de la chaîne PATH.
La fuite « : » est causé par le fait que vous définissez la fin de la ligne, pas le séparateur. J'utilise des unités limitted de ressources et, comme pour emballer le tout dans un seul script, sans ces bizarreries:
path_remove () {
PATH="$(echo -n $PATH | awk -v RS=: -v ORS= '$0 != "'$1'"{print s _ $0;s=":"}')"
}