web-dev-qa-db-fra.com

Suppression d'un répertoire de PATH

J'essaie de compiler wxWidgets en utilisant MingW, et j'ai cygwin sur mon chemin, ce qui semble être en conflit. Je voudrais donc supprimer /d/Programme/cygwin/bin à partir de la variable PATH et je me demande s'il existe une manière élégante de le faire.

L'approche naïve serait de l'écho dans un fichier, de le supprimer manuellement et de le source, mais je parie qu'il y a une meilleure approche à cela.

33
Devolus

Il n'y a pas d'outils standard pour "éditer" la valeur de $ PATH (c'est-à-dire "ajouter un dossier uniquement lorsqu'il n'existe pas déjà" ou "supprimer ce dossier"). Vous exécutez simplement:

export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

ce serait pour la session en cours, si vous voulez changer de façon permanente, ajoutez-le à n'importe quel .bashrc, bash.bashrc,/etc/profile - tout ce qui convient à votre système et aux besoins des utilisateurs. Cependant, si vous utilisez BASH, vous pouvez également effectuer les opérations suivantes si, disons, vous souhaitez supprimer le répertoire /home/wrong/dir/ à partir de votre variable PATH, en supposant que c'est à la fin:

PATH=$(echo "$PATH" | sed -e 's/:\/home\/wrong\/dir$//')

Donc, dans votre cas, vous pouvez utiliser

PATH=$(echo "$PATH" | sed -e 's/:\/d\/Programme\/cygwin\/bin$//')
28
tusharmakkar08

En bash:

directory_to_remove=/d/Programme/cygwin/bin
PATH=:$PATH:
PATH=${PATH//:$directory_to_remove:/:}
PATH=${PATH#:}; PATH=${PATH%:}

Si vous n'utilisez pas de variable intermédiaire, vous devez protéger le / caractères dans le répertoire à supprimer afin qu'ils ne soient pas traités comme la fin du texte de recherche.

PATH=:$PATH:
PATH=${PATH//:\/d\/Programme\/cygwin\/bin:/:}
PATH=${PATH#:}; PATH=${PATH%:}

La première et la troisième ligne sont là pour faire en sorte que chaque composant du chemin de recherche soit entouré par :, pour éviter de placer dans un boîtier spécial le premier et le dernier composant. La deuxième ligne supprime le composant spécifié.

Après avoir examiné les autres options présentées ici et ne pas avoir compris comment certaines d'entre elles fonctionnaient, j'ai développé mon propre path_remove, que j'ai ajoutée à mon .bashrc:

function path_remove {
  # Delete path by parts so we can never accidentally remove sub paths
  PATH=${PATH//":$1:"/":"} # delete any instances in the middle
  PATH=${PATH/#"$1:"/} # delete any instance at the beginning
  PATH=${PATH/%":$1"/} # delete any instance in the at the end
}

Cela s'est avéré assez proche de la solution de Gilles mais a été présenté comme une fonction bash qui pourrait être facilement utilisée sur la ligne de commande.

Il a les avantages qu'en tant que fonction bash, il fonctionne comme un programme sans avoir besoin d'être un programme sur le chemin, et il ne nécessite aucun programme externe pour s'exécuter, juste une manipulation de chaîne bash.

Il semble assez robuste, en particulier il ne tourne pas somepath:mypath/mysubpath en somepath/mysubpath: si vous exécutez path_remove mypath, qui était un problème que j'avais avec mon précédent path_remove une fonction.

Une excellente explication du fonctionnement de la manipulation de chaînes bash peut être trouvée dans le Advanced Bash-Scripting Guide .

9
Mark Booth

Donc, en combinant les réponses de @gilles et @ bruno-a (et quelques autres astuces sed), j'ai trouvé ce one-liner, qui supprimera (chaque) REMOVE_PART de PATH, qu'il se produise au début, milieu ou fin de CHEMIN

PATH=$(REMOVE_PART="/d/Programme/cygwin/bin" sh -c 'echo ":$PATH:" | sed "s@:$REMOVE_PART:@:@g;s@^:\(.*\):\$@\1@"')

C'est un peu lourd, mais c'est bien de pouvoir le faire en un seul coup. Le ; Est utilisé pour réunir les deux commandes sed distinctes:

  • s@:$REMOVE_PART:@:@g (Qui remplace :$REMOVE_PART: Par un seul :)
  • s@^:\(.*\):\$@\1@ (qui supprime les deux-points avant et arrière que nous avons ajoutés avec la commande echo)

Et dans le même ordre d'idées, je suis juste parvenu à trouver cette doublure pour ajouter un ADD_PART au PATH, seulement si le PATH ne le contient pas déjà

PATH=$(ADD_PART="/d/Programme/cygwin/bin" sh -c 'if echo ":$PATH:" | grep -q ":$ADD_PART:"; then echo "$PATH"; else echo "$ADD_PART:$PATH"; fi')

Remplacez la dernière partie par echo "$PATH:$ADD_PART" Si vous souhaitez ajouter ADD_PART à la fin de PATH plutôt qu'au début.

...

... ou pour rendre cela encore plus facile, créez un script appelé remove_path_part avec le contenu

echo ":$PATH:" | sed "s@:$1:@:@g;s@^:\(.*\):\$@\1@"

et un script appelé prepend_path_part avec le contenu

if echo ":$PATH:" | grep -q ":$1:"; then echo "$PATH"; else echo "$1:$PATH"; fi

et un script appelé append_path_part avec le contenu

if echo ":$PATH:" | grep -q ":$1:"; then echo "$PATH"; else echo "$PATH:$1"; fi

rendez-les tous exécutables, puis appelez-les comme:

  • PATH=$(remove_path_part /d/Programme/cygwin/bin)
  • PATH=$(prepend_path_part /d/Programme/cygwin/bin)
  • PATH=$(append_path_part /d/Programme/cygwin/bin)

Bien, même si je le dis moi-même :-)

7
Lurchman

Une doublure beaucoup plus simple.

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

5
user332870

C'est un exercice intéressant d'écrire une fonction bash pour supprimer un répertoire d'une variable de chemin.

Voici quelques fonctions que j'utilise dans mes fichiers .bash * pour ajouter/ajouter des répertoires aux chemins. Ils ont le mérite de supprimer les entrées en double, le cas échéant, et fonctionnent avec tout type de variable de chemin séparé par deux points (PATH, MANPATH, INFOPATH, ...). la fonction remove_from supprime le répertoire.

# {app,pre}pend_to path-var-name dirpath
# remove_from path-var-name dirpath
#
# Functions to manipulate a path-style variable.  {app,pre}pend_to
# both remove any other instances of dirname before adding it to
# the start or end of the path-var-name variable.
#
# Calling example:
#   append_to PATH "/usr/local/bin"
#
# Uses eval to allow target path varname to be passed in.
function remove_from() {
  # add surrounging colons
  eval tmp_path=":\$${1}:"
  # if dir is already there, remove it
  (echo "${tmp_path}" | grep --silent ":${2}:") &&
    tmp_path=`echo "$tmp_path" | sed "s=:${2}:=:=g"`
  # remove surrounding colons
  tmp_path=`echo "$tmp_path" | sed 's=^:==; s=:$=='`
  eval export $1=\"$tmp_path\"
}
function append_to() {
  remove_from "$1" "$2"  # clean the path contents
  eval export $1=\"\$${1}:$2\"
}
function prepend_to() {
  remove_from "$1" "$2"  # clean the path contents
  eval export $1=\"${2}:\$$1\"
}
2
Greg Tarsa

Voici le code révisé de la solution de Greg Tarsa. Seules les commandes intégrées bash sont utilisées ici. Ainsi, cela économisera beaucoup d'appels système fork ().

# Calling example:
#   append_to PATH "/usr/local/bin"

function remove_from()
{
    local path="${1}"
    local dir="${2}"
    local -a dirs=()
    local old_ifs="${IFS}"
    IFS=":"
    set -- ${!path}
    while [ "$#" -gt "0" ]
    do
        [ "${1}" != "${dir}" ] && dirs+=("${1}")
        shift
        done
    eval "export ${path}=\"${dirs[*]}\""
    IFS="${old_ifs}"
}

function append_to()
{
    remove_from "${1}" "${2}"
    [ -d "${2}" ] || return
    if [ -n "${!1}" ]
    then
        eval "export ${1}=\"${!1}:${2}\""
    else
        eval "export ${1}=\"${2}\""
    fi
}

function prepend_to()
{
    remove_from "${1}" "${2}"
    [ -d "${2}" ] || return
    if [ -n "${!1}" ]
    then
        eval "export ${1}=\"${2}:${!1}\""
    else
        eval "export ${1}=\"${2}\""
    fi
}
2
Jie Gong

Cette méthode gère le délimiteur de chemin de début/fin:

echo $PATH | sed 's/:/\n/g' | grep -v <path description> | xargs | tr ' ' ':'

Explication:

echo la variable $ PATH en sed qui remplace ':' par des sauts de ligne

grep la sortie et supprimez les lignes correspondant à notre requête

xargs la sortie pour remplacer les sauts de ligne par des espaces

tr la sortie pour remplacer les espaces par des deux-points

xargs gère le découpage des valeurs de fin

chaîne quelques greps pour supprimer un tas de chemins

1
anax32

Pour compléter/améliorer la réponse acceptée de Tushar, vous pouvez:

  • évitez d'avoir à échapper aux barres obliques dans le CHEMIN en utilisant des délimiteurs sans barre oblique
  • omettre le -e option, selon la page de manuel sed : "Si aucune option -e, --expression, -f ou --file n'est donnée, le premier argument sans option est pris comme script sed à interpréter. "
  • utilisez l'indicateur g (global) pour supprimer toutes les occurrences

En fin de compte, cela donne quelque chose comme ceci:

PATH=$(echo "$PATH" | sed 's@:/home/wrong/dir$@@g')
1
Bruno A.

Les réponses actuelles ne résolvent pas mon problème similaire en ce sens que je dois supprimer plusieurs chemins. Tous ces chemins sont des sous-répertoires d'un seul répertoire. Dans ce cas, ce one-liner fonctionne pour moi: (supposons que le modèle est cygwin, c'est-à-dire, en supprimant tous les chemins qui contiennent cygwin)

pattern=cygwin; export PATH=$(echo $PATH|tr ':' '\n'|sed "\#${pattern}#d" |tr '\n' ':')
0
Penghe Geng