Removendo um Diretório do PATH

28

Estou tentando compilar wxWidgets usando MingW e tenho cygwin no meu caminho, o que parece entrar em conflito. Então, eu gostaria de remover /d/Programme/cygwin/binda variável PATH e me pergunto se existe alguma maneira elegante de fazer isso.

A abordagem ingênua seria fazer eco em um arquivo, removê-lo manualmente e fonte-lo, mas eu aposto que há uma abordagem melhor para isso.

Devolus
fonte
2
Muitas técnicas estão listadas aqui: stackoverflow.com/questions/370047/…
slm

Respostas:

23

Não há ferramentas padrão para "editar" o valor de $ PATH (por exemplo, "adicionar pasta apenas quando ainda não existir" ou "remover esta pasta"). Você acabou de executar:

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

isso seria para a sessão atual, se você quiser alterá-lo permanentemente, adicione-o a qualquer perfil .bashrc, bash.bashrc, / etc / profile - o que for adequado ao seu sistema e às necessidades do usuário. No entanto, se você estiver usando o BASH, também poderá fazer o seguinte se, digamos, você desejar remover o diretório /home/wrong/dir/da sua variável PATH, supondo que esteja no final:

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

Então, no seu caso, você pode usar

PATH=$(echo "$PATH" | sed -e 's/:\/d\/Programme\/cygwin\/bin$//')
tusharmakkar08
fonte
1
Se o caminho em questão estiver no início da variável PATH, você precisará corresponder os dois pontos no final. Esta é uma advertência irritante que complica as manipulações genéricas fáceis das variáveis ​​PATH.
Graeme
4
Ao lidar com tantas barras, eu prefiro alterar o delimitador de expressão regular /com algo como |: PATH=$(echo "$PATH" | sed -e 's|:/d/Programme/cygwin/bin$||')para evitar toda a fuga.
Matthias Kuhn
17

Na festança:

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

Se você não usar uma variável intermediária, precisará proteger os /caracteres no diretório para remover, para que não sejam tratados como o final do texto da pesquisa.

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

A primeira e a terceira linha estão lá para organizar todos os componentes do caminho de pesquisa a serem cercados :, para evitar o revestimento especial do primeiro e do último componente. A segunda linha remove o componente especificado.

Gilles 'SO- parar de ser mau'
fonte
Obrigado @Gilles, sua resposta me levou a encontrar minha própria solução , que requer apenas três manipulações de PATH em vez de quatro. * 8 ')
Mark Booth
8

Depois de considerar outras opções apresentadas aqui, e sem entender completamente como algumas delas funcionavam, desenvolvi minha própria path_removefunção, que adicionei à minha .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
}

Isso acabou bem perto da solução de Gilles, mas foi encerrado como uma função bash que poderia ser facilmente usada na linha de comando.

Tem as vantagens de que, como uma função bash, funciona como um programa sem precisar ser um programa no caminho, e não requer a execução de programas externos, apenas a manipulação do bash string.

Parece bastante robusto, em particular, não se transforme somepath:mypath/mysubpathem somepath/mysubpath: se você executar path_remove mypath, o que era um problema que eu tive com o meu anterior path_removefunção.

Uma excelente explicação de como funciona a manipulação de string bash pode ser encontrada no Advanced Bash-Scripting Guide .

Mark Booth
fonte
6

Então, combinando as respostas de @gilles e @ bruno-a (e alguns outros truques de sed), criei essa linha única, que removerá (todos) REMOVE_PART do PATH, independentemente de ocorrer no início, meio ou fim do caminho

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

É um pouco pesado, mas é bom poder fazer isso em um único hit. O ;é usado para unir os dois comandos sed separados:

  • s@:$REMOVE_PART:@:@g(que substitui :$REMOVE_PART:por um único :)
  • s@^:\(.*\):\$@\1@ (que retira os dois pontos iniciais e finais que adicionamos com o comando echo)

E de maneira semelhante, eu apenas consegui criar essa linha para adicionar um ADD_PART ao PATH, apenas se o PATH ainda não o contiver.

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

Altere a última parte para echo "$PATH:$ADD_PART"se você deseja adicionar ADD_PART ao final de PATH em vez de ao início.

...

... ou para facilitar ainda mais, crie um script chamado remove_path_partcom o conteúdo

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

e um script chamado prepend_path_partcom o conteúdo

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

e um script chamado append_path_partcom o conteúdo

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

torne-os todos executáveis ​​e, em seguida, chame-os como:

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

Legal, mesmo que eu diga :-)

Lurchman
fonte
Gosto da sugestão, principalmente da ideia dos scripts.
precisa saber é o seguinte
3

Um forro muito mais simples.

exportar PATH = `eco $ PATH | tr ":" "\ n" | grep -v "anaconda" | tr "\ n" ":" `

user332870
fonte
2

É um exercício interessante escrever uma função bash para remover um diretório de uma variável de caminho.

Aqui estão algumas funções que eu uso nos meus arquivos .bash * para acrescentar / acrescentar diretórios aos caminhos. Eles têm a virtude de remover entradas duplicadas, se houver, e funcionam com qualquer tipo de variável de caminho separado por dois pontos (PATH, MANPATH, INFOPATH, ...). a função remove_from remove o diretório

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

Abaixo estão os códigos revisados ​​da solução de Greg Tarsa. Somente comandos bash build-in são usados ​​aqui. Assim, ele economizará muitas chamadas de 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
}
Jie Gong
fonte
1

Para concluir / melhorar a resposta aceita de Tushar, você pode:

  • evite ter que escapar das barras no PATH usando delimitadores não-barra
  • omita a -eopção, de acordo com a página do manual sed : "Se nenhuma opção -e, --expression, -f ou --file for fornecida, o primeiro argumento de não opção será usado como o script sed para interpretar."
  • use o gsinalizador (global) para remover todas as ocorrências

No final, fornece algo parecido com isto:

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

As respostas atuais não resolvem meu problema semelhante, pois preciso remover vários caminhos. Todos esses caminhos são subdiretórios de um único diretório. Nesse caso, essa linha única funciona para mim: (suponha que o padrão esteja cygwinremovendo todos os caminhos que contêm cygwin)

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