Rimozione di una directory da PATH


28

Sto cercando di compilare wxWidgets usando MingW e ho Cygwin nel mio percorso, che sembra essere in conflitto. Quindi vorrei rimuovere /d/Programme/cygwin/bindalla variabile PATH e mi chiedo se esiste un modo elegante per farlo.

L'approccio ingenuo sarebbe quello di riecheggiarlo in un file, rimuoverlo manualmente e sorgente, ma scommetto che c'è un approccio migliore a questo.


2
Molte tecniche sono elencate qui: stackoverflow.com/questions/370047/…
slm

Risposte:


23

Non esistono strumenti standard per "modificare" il valore di $ PATH (ovvero "aggiungi cartella solo quando non esiste già" o "rimuovi questa cartella"). Devi solo eseguire:

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

questo sarebbe per la sessione corrente, se vuoi cambiarlo in modo permanente aggiungilo a qualsiasi profilo .bashrc, bash.bashrc, / etc / profile - qualunque cosa si adatti al tuo sistema e alle tue esigenze dell'utente. Tuttavia, se stai usando BASH, puoi anche fare quanto segue se, diciamo, vuoi rimuovere la directory /home/wrong/dir/dalla tua variabile PATH, supponendo che sia alla fine:

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

Quindi nel tuo caso puoi usare

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

1
Se il percorso in questione si trova all'inizio della variabile PATH, è necessario abbinare i due punti alla fine. Questo è un avvertimento fastidioso che complica semplici manipolazioni generiche delle variabili PATH.
Graeme,

4
Quando ho a che fare con così tante barre preferisco cambiare il delimitatore regex /con qualcosa del genere |: PATH=$(echo "$PATH" | sed -e 's|:/d/Programme/cygwin/bin$||')per evitare tutte le fughe.
Matthias Kuhn,

17

In bash:

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

Se non si utilizza una variabile intermedia, è necessario proteggere i /caratteri nella directory da rimuovere in modo che non vengano trattati come la fine del testo di ricerca.

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

La prima e la terza riga sono lì per disporre di circondare ogni componente del percorso di ricerca :, per evitare il caso speciale del primo e dell'ultimo componente. La seconda riga rimuove il componente specificato.


Grazie @Gilles, la tua risposta mi ha spinto a trovare la mia soluzione , che richiede solo tre manipolazioni di PATH anziché quattro. * 8 ')
Mark Booth,

8

Dopo aver considerato le altre opzioni presentate qui e non aver compreso appieno il funzionamento di alcuni di essi, ho sviluppato la mia path_removefunzione, che ho aggiunto al mio .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
}

Questo finì abbastanza vicino alla soluzione di Gilles, ma racchiuso in una funzione bash che poteva essere facilmente usata dalla riga di comando.

Ha i vantaggi che come funzione bash funziona come un programma senza la necessità di essere un programma sul percorso e non richiede l'esecuzione di alcun programma esterno, ma solo la manipolazione della stringa bash.

Sembra piuttosto robusto, in particolare non si trasforma somepath:mypath/mysubpathin somepath/mysubpath: se corri path_remove mypath, che era un problema che avevo con la mia path_removefunzione precedente .

Un'eccellente spiegazione del funzionamento della manipolazione di stringhe bash è disponibile nella Guida avanzata di script Bash .


6

Quindi, combinando le risposte di @gilles e @ bruno-a (e un paio di altri trucchi per sed) ho ideato questo one-liner, che rimuoverà (ogni) REMOVE_PART da PATH, indipendentemente dal fatto che si verifichi all'inizio, metà o fine del PERCORSO

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

È un po 'ingombrante, ma è bello poterlo fare in un colpo solo. La ;viene utilizzato per unire insieme i due comandi separati sed:

  • s@:$REMOVE_PART:@:@g(che sostituisce :$REMOVE_PART:con un singolo :)
  • s@^:\(.*\):\$@\1@ (che rimuove i due punti iniziali e finali aggiunti con il comando echo)

E seguendo linee simili, sono appena riuscito a trovare questo one-liner per aggiungere un ADD_PART al PERCORSO, solo se il PERCORSO non lo contiene già

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')

Modificare l'ultima parte in echo "$PATH:$ADD_PART"se si desidera aggiungere ADD_PART alla fine di PATH anziché all'inizio.

...

... o per renderlo ancora più semplice, crea uno script chiamato remove_path_partcon il contenuto

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

e uno script chiamato prepend_path_partcon il contenuto

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

e uno script chiamato append_path_partcon il contenuto

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

rendili tutti eseguibili e quindi chiamali come:

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

Pulito, anche se lo dico io stesso :-)


Mi piace il suggerimento, in particolare l'idea con gli script.
Devolus,

3

Una fodera molto più semplice.

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


2

È un esercizio interessante scrivere una funzione bash per rimuovere una directory da una variabile di percorso.

Ecco alcune funzioni che utilizzo nei miei file .bash * per aggiungere / anteporre directory ai percorsi. Hanno la virtù di rimuovere eventuali voci duplicate e funzionano con qualsiasi tipo di variabile di percorso separata da due punti (PATH, MANPATH, INFOPATH, ...). la funzione remove_from rimuove la directory.

# {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

Di seguito sono riportati i codici revisionati dalla soluzione di Greg Tarsa. Qui vengono utilizzati solo i comandi di build bash. Pertanto, salverà molte chiamate di sistema 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
}

1

Per completare / migliorare la risposta accettata da Tushar, puoi:

  • evitare di dover sfuggire alle barre nel PERCORSO utilizzando delimitatori non-barra
  • ometti l' -eopzione, come nella pagina man di sed : "Se viene fornita l'opzione -e, --expression, -f o --file, il primo argomento non-opzione viene preso come script sed da interpretare".
  • usa il gflag (globale) per rimuovere tutte le occorrenze

Alla fine, dà qualcosa del genere:

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

0

Le risposte attuali non risolvono il mio problema simile in quanto devo rimuovere più percorsi. Tutti questi percorsi sono sottodirectory di una singola directory. In tal caso, questo one-liner funziona per me: (supponiamo che lo schema sia cygwin, cioè, la rimozione di tutti i percorsi che contiene cygwin)

pattern=cygwin; export PATH=$(echo $PATH|tr ':' '\n'|sed "\#${pattern}#d" |tr '\n' ':')
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.