Suppression d'un répertoire de PATH

28

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/binde 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.

Devolus
la source
2
De nombreuses techniques sont répertoriées ici: stackoverflow.com/questions/370047/…
slm

Réponses:

23

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/de votre variable PATH, en supposant qu'il se trouve à 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$//')
tusharmakkar08
la source
1
Si le chemin en question se trouve au début de la variable PATH, vous devez faire correspondre les deux-points à la fin. Il s'agit d'une mise en garde ennuyeuse qui complique les manipulations génériques faciles des variables PATH.
Graeme
4
Lorsque je traite autant de barres obliques, je préfère changer le délimiteur d'expressions régulières /avec quelque chose comme |: PATH=$(echo "$PATH" | sed -e 's|:/d/Programme/cygwin/bin$||')pour empêcher tout échappement.
Matthias Kuhn
17

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 les /caractères du 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é :, pour éviter de mettre en casse spéciale le premier et le dernier composant. La deuxième ligne supprime le composant spécifié.

Gilles 'SO- arrête d'être méchant'
la source
Merci @Gilles, votre réponse m'a incité à trouver ma propre solution , qui ne nécessite que trois manipulations de PATH plutôt que quatre. * 8 ')
Mark Booth
8

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é ma propre path_removefonction, que j'ai ajoutée à ma .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 s'est 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 se transforme pas somepath:mypath/mysubpathen somepath/mysubpath: si vous exécutez path_remove mypath, ce qui était un problème que j'ai eu avec ma path_removefonction précédente .

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

Mark Booth
la source
6

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 agréable 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, uniquement 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_partavec le contenu

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

et un script appelé prepend_path_partavec le contenu

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

et un script appelé append_path_partavec 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 :-)

Lurchman
la source
J'aime la suggestion, en particulier l'idée avec les scripts.
Devolus
3

Une doublure beaucoup plus simple.

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

user332870
la source
2

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\"
}
Greg Tarsa
la source
2

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
}
Jie Gong
la source
1

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

  • éviter d'avoir à échapper aux barres obliques dans le CHEMIN en utilisant des délimiteurs non-barre oblique
  • omettez l' -eoption, conformément à la page de manuel sed : "Si aucune option -e, --expression, -f ou --file n'est donnée, le premier argument de non-option est considéré comme le script sed à interpréter."
  • utilisez l' gindicateur (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')
Bruno A.
la source
0

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 motif soit 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' ':')
Penghe Geng
la source