Remova caminhos redundantes da variável $ PATH

125

Eu defini o mesmo caminho na variável $ PATH 6 vezes.

Eu não estava saindo para verificar se funcionava.

Como posso remover as duplicatas?

A variável $ PATH se parece com isso:

echo $PATH

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/home/flacs/Programmes/USFOS/bin:/home/flacs/Programmes/USFOS/bin:/home/flacs/Programmes/USFOS/bin:/home/flacs/Programmes/USFOS/bin:/home/flacs/Programmes/USFOS/bin:/home/flacs/Programmes/USFOS/bin

Como eu redefini-lo para apenas

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
charles hendry
fonte
onde você definiu 6 vezes? em quais arquivos?
hovanessyan

Respostas:

122

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.

Nota: Isto é para Linux. Vamos deixar isso claro para novos codificadores. (`, ') Não tente SET = estes.

hovanessyan
fonte
sim, eu os defino permanentemente no bash.bashrc. Então, o comando deve ser algo assim? echo 'export PATH=$PATH:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games' >> ~/.bashrc
Charles Hendry
o fato é que, dependendo do seu sistema operacional, uma cadeia de configurações é executada. Você precisa garantir que a variável PATH não seja substituída posteriormente. A maneira mais fácil de fazer isso (para um usuário) é substituí-lo no .bashrc pessoal do usuário, que geralmente está localizado em seu diretório pessoal.
hovanessyan
1
seu comando define o PATH para - $ PATH (o valor atual de PATH) + a cadeia / usr / local / sbin: / usr / local / bin: / usr / sbin: / usr / bin: / sbin: / bin: / usr / gam‌ es. Se você deseja ter apenas a String, remova $ PATH + o ponto e vírgula (:) do seu comando. Não importa se você usa eco ou edita o arquivo ~ / .bashrc manualmente.
hovanessyan
o arquivo bash.bashrc está localizado na pasta / etc. Ele não exibe a variável $ PATH, então eu não tenho certeza se para editá-lo
Charles Hendry
no seu primeiro comentário, você faz eco para ~ / .bashrc (citando: >> ~ / .bashrc), não para /etc/bash.bashrc. Se você deseja alterar o PATH para um usuário específico, edite-o em / home / <o nome do usuário> / .bashrc. o /etc/bash.bashrc se aplica a todos os usuários.
219122 hovanessyan
70

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 PATHvariável:

PATH=`echo $PATH | sed -e 's/:\/home\/wrong\/dir\/$//'`
sufinawaz
fonte
1
Isso foi útil para mim, pois um diretório foi adicionado no / etc / profile que eu desejava excluir, mas não tinha acesso de gravação ao / etc. Obrigado :)
Samizdis
13
Protip: você pode usar diferentes delimitadores na expressão sed para evitar o \ / escape:PATH=$(echo $PATH | sed -e 's|:/home/wrong/dir|$||')
iNecas
4
Esse truque ajuda quando eu quero ter um novo PATH imediatamente e não quero sair do terminal atual. No entanto, para evitar confusão, deve-se experimentar o comando de geração PATH (ou seja echo $PATH | sed -e 's/:\/home\/wrong\/dir\/$//') antes de atribuí-lo ao PATH.
Biocyberman
2
Isso não funcionará quando o caminho a ser excluído for o primeiro $PATH. Use este:PATH=$(echo :$PATH: | sed -e 's,:/home/wrong/dir:,:,g' -e 's/^://' -e 's/:$//')
Robin Hsu
não funcionou $ PATH=eco $ PATH | sed -e 's /: \ / scratch \ / SJN \ / anaconda \ / bin \ / python \ / $ //' `` para remover / scratch / SJN / anaconda / bin / python
Mona Jalal
13

Linux: remova caminhos redundantes da variável $ PATH

O Linux From Scratch possui esta função em / 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"
}

Isso deve ser usado com essas funções para adicionar ao caminho, para que você não faça isso de forma redundante:

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"
}

O uso simples é fornecer apenas pathremoveo caminho do diretório a ser removido - mas lembre-se de que ele deve corresponder exatamente:

$ pathremove /home/username/anaconda3/bin

Isso removerá cada instância desse diretório do seu caminho.

Se você deseja que o diretório esteja no seu caminho, mas sem as redundâncias, você pode apenas usar uma das outras funções, por exemplo - para o seu caso específico:

$ pathprepend /usr/local/sbin
$ pathappend /usr/local/bin
$ pathappend /usr/sbin
$ pathappend /usr/bin
$ pathappend /sbin
$ pathappend /bin
$ pathappend /usr/games

Mas, a menos que a legibilidade seja a preocupação, neste momento é melhor você apenas fazer:

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

Isso funcionaria em todas as conchas conhecidas pelo homem?

Eu presumo que o acima para o trabalho na sh, dashe, bashpelo menos. Eu ficaria surpreso ao saber que não funciona csh,fish', or ksh`. Duvido que funcionaria no shell de comando do Windows ou no Powershell.

Se você possui o Python, o seguinte tipo de comando deve fazer o que é solicitado diretamente (ou seja, remover caminhos redundantes):

$ PATH=$( python -c "
import os
path = os.environ['PATH'].split(':')
print(':'.join(sorted(set(path), key=path.index)))
" )

Um one-liner (para evitar problemas de múltiplas linhas):

$ PATH=$( python -c "import os; path = os.environ['PATH'].split(':'); print(':'.join(sorted(set(path), key=path.index)))" )

O acima remove os caminhos redundantes posteriores. Para remover caminhos redundantes anteriores, use o índice de uma lista invertida e inverta-o novamente:

$ PATH=$( python -c "
import os
path = os.environ['PATH'].split(':')[::-1]
print(':'.join(sorted(set(path), key=path.index, reverse=True)))
" )
Aaron Hall
fonte
+1. pathremove () funciona em todos os tipos de shell, como csh, ksh, bash etc? btw, meu / etc / profile no RHEL não tem partremove (), mas apenas pathmunge ().
Tagar 21/10/19
1
@Tagar Não dou garantias de compatibilidade com todos os outros shells. Sugiro testá-lo em qualquer shell que você estiver usando e, se não funcionar no seu shell, você poderá usar o Python se o tiver instalado - adicionei um pouco de Python à resposta para descrever como.
Aaron Hall
Se eu ler "3.5.3 Shell Parameter Expansion" corretamente, ${!PATHVARIABLE}é um tipo de variável indireta, mas não sei ao certo como funciona aqui. Você poderia explicar isso por favor?
Loxaxs
@loxaxs Essa é uma variável local nessas funções bash, declarada com o localbuiltin (que só pode ser usado dentro de uma função.) Se você tiver outras dúvidas, provavelmente deverá fazer uma nova pergunta no site (depois de pesquisá-la primeiro para garantir você não está criando uma duplicata exata ...).
Aaron Hall
Esta é uma resposta realmente interessante, obrigado pela redação! No entanto, a questão original de limpar uma variável PATH bagunçada parece não ter sido resolvida com elegância (apesar de, eu admito, então, ao usar essas funções, não haveria um PATH bagunçado para começar).
Christian Herenz
9

Aqui está um código de uma linha que limpa o PATH

  • Não perturba a ordem do PATH, apenas remove duplicatas
  • Guloseimas: e o PATH graciosamente
  • Nenhum caractere especial usado, portanto, não requer escape
  • Usa /bin/awkpara que funcione mesmo quando PATH está quebrado

    export PATH="$(echo "$PATH" |/bin/awk 'BEGIN{RS=":";}
    {sub(sprintf("%c$",10),"");if(A[$0]){}else{A[$0]=1;
    printf(((NR==1)?"":":")$0)}}')";
GreenFox
fonte
1
alguém testou? é seguro?
Joe RR
2
Se você não tem awk instalado, ele limpa o seu caminho, eu aconselho a copiar o seu caminho para um arquivo txt antes com echo $ PATH
José Pita
Não funciona para mim ... Eu tenho o awk instalado, mas algumas duplicatas não são removidas.
Christian Herenz
3
  1. Somente echo $PATH
  2. copiar detalhes em um editor de texto
  3. remover entradas indesejadas
  4. PATH= # pass new list of entries
mrwagaba
fonte
2

Se você deseja remover todos os caminhos duplicados, eu uso este script que escrevi há algum tempo, pois estava tendo problemas com vários caminhos perl5 / bin:

#!/bin/bash
#
# path-cleanup
#
# This must be run as "source path-cleanup" or ". path-cleanup"
# so the current shell gets the changes.

pathlist=`echo $PATH | sed 's/:/\n/g' | uniq`

# echo "Starting PATH: $PATH"
# echo "pathlist: $pathlist"
unset PATH
# echo "After unset, PATH: $PATH"
for dir in $pathlist
do
    if test -d $dir ; then
        if test -z $PATH; then
            PATH=$dir
        else
            PATH=$PATH:$dir
        fi
    fi
done
export PATH
# echo "After loop, PATH: $PATH"

E eu coloquei no meu ~ / .profile no final. Desde que eu uso o BASH quase exclusivamente, eu não tentei em outros reservatórios.

Kevin Nathan
fonte
1
+1 para a solução. Aliás, ele removerá apenas os caminhos de duplicação se eles estiverem na lista um após o outro. Você pode mudar |uniqpara |sort|uniqcorrigir isso, mas isso mudará a ordem de todos os diretórios no caminho, o que não acho que seja um efeito colateral desejável.
Tagar
1

Supondo que seu shell seja o Bash, você pode definir o caminho com

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

mas, como Levon disse em outra resposta, assim que você encerrar o shell, as alterações desaparecerão. Você provavelmente deseja configurar seu PATHin ~/.bash_profileou ~/.bashrc.

Leo
fonte
1

No bash, você pode simplesmente $ {var / find / replace}

PATH=${PATH/%:\/home\/wrong\/dir\//}

Ou, neste caso (como o bit de substituição está vazio), basta:

PATH=${PATH%:\/home\/wrong\/dir\/}

Eu vim aqui primeiro, mas fui outra mercadoria, pois pensei que haveria uma expansão de parâmetros para fazer isso. Mais fácil que o sed !.

Como substituir o caractere de marcador ou palavra na variável pelo valor de outra variável no Bash?

sabgenton
fonte
%significa match se no final da string #for o começo.
sabgenton
0

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

Para verificar qual seria o caminho ao fazer login na próxima vez, use telnet localhost(outelnet 127.0.0.1 ). Ele solicitará seu nome de usuário e senha.

Isso fornece um novo shell de login (ou seja, um completamente novo que não herda nada do ambiente atual).

Você pode verificar o valor de $PATHlá e editar seus arquivos rc até que esteja correto. Isso também é útil para verificar se você pode efetuar login novamente após fazer uma alteração em um arquivo importante.

Aaron Digulla
fonte
Em vez de digitar o nome de usuário / senha, basta digitar /bin/bash -i. Muito menos aborrecimento.
Ed Heal #:
0

Como você adicionou esses caminhos duplicados à sua variável PATH? Você deve ter editado um dos seus .arquivos. ( .tcshrc, ou.bashrc etc, dependendo do seu sistema / shell). A maneira de corrigi-lo é editar o arquivo novamente e remover os caminhos duplicados.

Se você não editou nenhum arquivo e deve ter modificado o PATH interativamente. Nesse caso, as alterações não serão "mantidas", ou seja, se você abrir outro shell ou se desconectar e se conectar novamente, as alterações desaparecerão automaticamente.

Observe que também existem alguns arquivos de configuração em todo o sistema, mas é improvável que você os modifique; portanto, provavelmente você alterará os arquivos no diretório pessoal pessoal (se desejar tornar essas alterações permanentes depois de definir um conjunto de caminhos)

Levon
fonte
0

Para um modelo fácil de copiar e colar, eu uso este snippet Perl:

PATH=`echo $PATH | perl -pe s:/path/to/be/excluded::`

Dessa forma, você não precisa escapar das barras para o operador substituto.

Alexander Shcheblikin
fonte