Como adicionar corretamente um caminho ao PATH?


922

Eu estou querendo saber onde um novo caminho deve ser adicionado à PATHvariável de ambiente. Eu sei que isso pode ser conseguido editando .bashrc(por exemplo), mas não está claro como fazer isso.

Deste jeito:

export PATH=~/opt/bin:$PATH

ou isto?

export PATH=$PATH:~/opt/bin

printf '\ nPATH = $ PATH: "caminho a adicionar" \ nexport PATH \ n' >> ~ / .bashrc
Sudoer


Se já existem alguns caminhos adicionados, por exemplo PATH=$PATH:$HOME/.local/bin:$HOME/bin, outro pode ser adicionado, separando com um: por exemplo PATH=$PATH:$HOME/.local/bin:$HOME/bin:/home/ec2-user/pear/bin.
Sandeepan Nath

2
Essas respostas funcionam para todos os sabores do linux?
Ungeheuer #

Respostas:


1032

As coisas simples

PATH=$PATH:~/opt/bin

ou

PATH=~/opt/bin:$PATH

dependendo se você deseja adicionar ~/opt/binno final (a ser pesquisado após todos os outros diretórios, caso haja um programa com o mesmo nome em vários diretórios) ou no início (a ser pesquisado antes de todos os outros diretórios).

Você pode adicionar várias entradas ao mesmo tempo. PATH=$PATH:~/opt/bin:~/opt/node/binou variações na encomenda funcionam perfeitamente. Não coloque exportno início da linha, pois ela possui complicações adicionais (veja abaixo em "Notas sobre conchas que não sejam do bash").

Se você PATHfor criado por muitos componentes diferentes, poderá acabar com entradas duplicadas. Consulte Como adicionar o caminho do diretório inicial a ser descoberto pelo Unix, que comando? e Remova entradas duplicadas $ PATH com o comando awk para evitar adicionar duplicatas ou removê-las.

Algumas distribuições automaticamente colocam ~/binno seu PATH, se existir, a propósito.

Onde colocá-lo

Coloque a linha de modificar PATHem ~/.profile, ou ~/.bash_profilese é o que você tem.

Observe que ~/.bash_rcnão é lido por nenhum programa e ~/.bashrcé o arquivo de configuração de instâncias interativas do bash. Você não deve definir variáveis ​​de ambiente em ~/.bashrc. O lugar certo para definir variáveis ​​de ambiente como PATHis ~/.profile(ou ~/.bash_profilese você não se importa com shells que não sejam o bash). Consulte Qual é a diferença entre eles e qual devo usar?

Não o coloque /etc/environmentou ~/.pam_environment: estes não são arquivos shell, você não pode usar substituições como as que estão $PATHlá. Nesses arquivos, você pode substituir apenas uma variável, não adicionar a ela.

Possíveis complicações em alguns scripts do sistema

Você não precisa exportse a variável já estiver no ambiente: qualquer alteração no valor da variável é refletida no ambiente.¹ PATHé praticamente sempre no ambiente; todos os sistemas unix definem isso muito cedo (geralmente no primeiro processo, de fato).

No momento do login, você pode confiar em PATHjá estar no ambiente e já conter alguns diretórios do sistema. Se você estiver escrevendo um script que pode ser executado mais cedo enquanto a criação de algum tipo de ambiente virtual, pode ser necessário para garantir que PATHnão é vazio e exportados: se PATHainda não está definido, então algo como PATH=$PATH:/some/directoryiria definir PATHa :/some/directory, e o componente vazia no começo significa o diretório atual (como .:/some/directory).

if [ -z "${PATH-}" ]; then export PATH=/usr/local/bin:/usr/bin:/bin; fi

Notas sobre conchas que não sejam o bash

No bash, ksh e zsh, exporthá uma sintaxe especial, e ambos PATH=~/opt/bin:$PATHe export PATH=~/opt/bin:$PATHfazem a coisa certa mesmo. Em outros shells no estilo Bourne / POSIX, como o dash (que está /bin/shem muitos sistemas), exporté analisado como um comando comum, o que implica duas diferenças:

Assim, em shells como dash, export PATH=~/opt/bin:$PATHdefine PATHa string literal ~/opt/bin/:seguida pelo valor de PATHaté o primeiro espaço. PATH=~/opt/bin:$PATH(uma tarefa simples) não requer aspas e faz a coisa certa. Se você deseja usar exportem um script portátil, precisa escrever export PATH="$HOME/opt/bin:$PATH", ou PATH=~/opt/bin:$PATH; export PATH(ou PATH=$HOME/opt/bin:$PATH; export PATHpara portabilidade, até o shell Bourne que não aceitou export var=valuee não fez expansão de til).

¹ Isso não era verdade nos reservatórios Bourne (como no reservatório Bourne real, não nos reservatórios modernos do estilo POSIX), mas é altamente improvável que você encontre esses reservatórios antigos hoje em dia.


Ainda não é capaz de entender a complicação da exportação. você pode simplificá-lo?
priojeet priyom 12/07

@priojeetpriyom Explicação simples: você não precisa export.
Gilles

Obrigado por esta resposta, perfeitamente detalhada. Você diz " Você não deve definir variáveis ​​de ambiente em ~ / .bashrc ", mas infelizmente 100% dos programas que instalei no meu sistema que modificam o caminho (FZF e Rust's Cargo) modificam o caminho .bashrc. Presumo que o FZF também esteja escrito em Rust e esteja seguindo o padrão de Rust.
icc97 30/07

83

De qualquer maneira, funciona, mas eles não fazem a mesma coisa: os elementos de PATHsão verificados da esquerda para a direita. No seu primeiro exemplo, os executáveis ​​em ~/opt/binterão precedência sobre os instalados, por exemplo, em /usr/bin, que pode ou não ser o que você deseja.

Em particular, do ponto de vista da segurança, é perigoso adicionar caminhos à frente, porque se alguém puder obter acesso de gravação ao seu ~/opt/bin, poderá colocar, por exemplo, um diferente lslá dentro, que você provavelmente usaria em vez disso de /bin/lssem perceber. Agora imagine o mesmo para o sshseu navegador ou escolha ... (O mesmo vale três vezes para colocar. No seu caminho.)


6
Mas se você quiser ter sua própria versão personalizada ls, precisará colocá-la em um diretório antes /bin.
Barmar 17/09/2015

16
ou alias ls = myls
waltinator 18/09/15

37

Estou confuso com a pergunta 2 (desde que removida da pergunta por se tratar de um problema não relacionado):

O que é uma maneira viável de acrescentar mais caminhos em linhas diferentes? Inicialmente, pensei que isso poderia funcionar:

export PATH=$PATH:~/opt/bin
export PATH=$PATH:~/opt/node/bin

mas não porque a segunda tarefa não apenas anexa ~/opt/node/bin, mas também a totalidade PATHatribuída anteriormente.

Esta é uma solução possível:

export PATH=$PATH:~/opt/bin:~/opt/node/bin

mas, para facilitar a leitura, prefiro ter uma atribuição para um caminho.

Se você diz

PATH=~/opt/bin

isso é tudo o que estará no seu caminho. PATH é apenas uma variável de ambiente e, se você deseja adicionar ao PATH, precisa reconstruir a variável exatamente com o conteúdo que deseja. Ou seja, o que você dá como exemplo para a pergunta 2 é exatamente o que você quer fazer, a menos que eu esteja totalmente esquecido do ponto da questão.

Eu uso os dois formulários no meu código. Eu tenho um perfil genérico que eu instalo em todas as máquinas em que trabalho que se parece com isso, para acomodar os diretórios que potencialmente estão ausentes:

export PATH=/opt/bin:/usr/local/bin:/usr/contrib/bin:/bin:/usr/bin:/usr/sbin:/usr/bin/X11
# add optional items to the path
for bindir in $HOME/local/bin $HOME/bin; do
    if [ -d $bindir ]; then
        PATH=$PATH:${bindir}
    fi
done

2
Você está certo sobre o exemplo da pergunta 2, ele funciona. Outro problema relacionado ao PATH no meu sistema me confundiu. Desculpe por isso.
Paolo

26

A maneira à prova de balas de Anexar / Anexar

Há muitas considerações envolvidas na escolha de anexar versus anexar. Muitos deles são abordados em outras respostas, portanto não os repetirei aqui.

Um ponto importante é que, mesmo que os scripts do sistema não usem isso (pergunto-me por que) * 1 , a maneira à prova de balas para adicionar um caminho (por exemplo, $HOME/bin) à variável de ambiente PATH é

PATH="${PATH:+${PATH}:}$HOME/bin"

para anexar (em vez de PATH="$PATH:$HOME/bin") e

PATH="$HOME/bin${PATH:+:${PATH}}"

para anexar (em vez de PATH="$HOME/bin:$PATH")

Isso evita o cólon espúrio inicial / final quando $PATHestá vazio, o que pode ter efeitos colaterais indesejados e pode se tornar um pesadelo , difícil de encontrar ( esta resposta trata brevemente do caso awk).

Explicação (da expansão de parâmetros do shell ):

${parameter:+word}

Se parameterfor nulo ou não definido, nada será substituído; caso contrário, a expansão de wordserá substituída.

Assim, ${PATH:+${PATH}:}é expandido para: 1) nada, se PATHfor nulo ou não definido , 2) ${PATH}:, se PATHestiver definido.

Nota : Isto é para bash.


* 1 Acabei de descobrir que scripts como devtoolset-6/enablerealmente usam isso,

$ cat /opt/rh/devtoolset-6/enable
# General environment variables
export PATH=/opt/rh/devtoolset-6/root/usr/bin${PATH:+:${PATH}}
...

24

O Linux determina o caminho da pesquisa executável com a $PATHvariável de ambiente. Para adicionar diretório / data / myscripts ao início da $PATHvariável de ambiente, use o seguinte:

PATH=/data/myscripts:$PATH

Para adicionar esse diretório ao final do caminho, use o seguinte comando:

PATH=$PATH:/data/myscripts

Mas o anterior não é suficiente porque, quando você define uma variável de ambiente dentro de um script, essa alteração é efetiva apenas dentro do script. Existem apenas duas maneiras de contornar essa limitação:

  • Se dentro do script, você exportar a variável de ambiente, ela será efetiva em qualquer programa chamado pelo script. Observe que não é eficaz no programa que chamou o script.
  • Se o programa que chama o script faz isso por inclusão em vez de chamada, qualquer alteração no ambiente do script é efetiva no programa de chamada. Essa inclusão pode ser feita com o comando dot ou o comando source.

Exemplos:

$HOME/myscript.sh
source $HOME/myscript.sh

A inclusão basicamente incorpora o script "chamado" no script "chamado". É como um #include em C. Portanto, é eficaz dentro do script ou programa "chamado". Mas é claro que não é eficaz em nenhum programa ou script chamado pelo programa de chamada. Para torná-lo eficaz em toda a cadeia de chamadas, você deve seguir a configuração da variável de ambiente com um comando de exportação.

Como exemplo, o programa bash shell incorpora o conteúdo do arquivo .bash_profile por inclusão. Coloque as 2 linhas a seguir em .bash_profile:

PATH=$PATH:/data/myscripts
export PATH

efetivamente coloca essas duas linhas de código no programa bash. Portanto, no bash, a variável $ PATH inclui $HOME/myscript.she, devido à instrução de exportação, todos os programas chamados pelo bash têm a $PATHvariável alterada . E como todos os programas executados a partir de um prompt do bash são chamados pelo bash, o novo caminho está em vigor para qualquer coisa que você execute a partir do prompt do bash.

A linha inferior é que, para adicionar um novo diretório ao caminho, você deve anexar ou anexar o diretório à variável de ambiente $ PATH em um script incluído no shell e exportar a $PATHvariável de ambiente.

Mais informações aqui


19

Há algum tempo, eu mantive comigo duas funções pathadde pathrmque ajudam a adicionar elementos ao caminho sem a necessidade de se preocupar com duplicações.

pathaddusa um argumento de caminho único e um afterargumento opcional que, se fornecido, será anexado ao PATHcaso contrário, ele será anexado .

Em quase todas as situações, se você estiver adicionando ao caminho, provavelmente desejará substituir qualquer coisa que já esteja no caminho, e é por isso que opto por prefixar por padrão.

pathadd() {
    newelement=${1%/}
    if [ -d "$1" ] && ! echo $PATH | grep -E -q "(^|:)$newelement($|:)" ; then
        if [ "$2" = "after" ] ; then
            PATH="$PATH:$newelement"
        else
            PATH="$newelement:$PATH"
        fi
    fi
}

pathrm() {
    PATH="$(echo $PATH | sed -e "s;\(^\|:\)${1%/}\(:\|\$\);\1\2;g" -e 's;^:\|:$;;g' -e 's;::;:;g')"
}

Coloque-os em qualquer script que você deseja alterar o ambiente PATH e agora você pode fazer.

pathadd "/foo/bar"
pathadd "/baz/bat" after
export PATH

Você está garantido para não adicionar ao caminho se ele já estiver lá. Se você agora deseja garantir /baz/batestá no início.

pathrm "/baz/bat"
pathadd "/baz/bat"
export PATH

Agora qualquer caminho pode ser movido para a frente, se já estiver no caminho sem dobrar.


Abordagem relacionada e mais limpa para verificar a presença de um diretório em seu PATH: unix.stackexchange.com/a/32054/135943
Wildcard

9

Não posso falar por outras distribuições, mas o Ubuntu possui um arquivo / etc / environment, que é o caminho de pesquisa padrão para todos os usuários. Como meu computador é usado apenas por mim, coloquei todos os diretórios desejados no caminho, a menos que seja uma adição temporária que coloquei em um script.


6

Existem algumas situações em que o uso PATH=/a/b:$PATHpode ser considerado a maneira "incorreta" de adicionar um caminho para PATH:

  1. Adicionando um caminho que não é realmente um diretório.
  2. Adicionando um caminho que já está PATHno mesmo formulário.
  3. Adicionando um caminho relativo (uma vez que o diretório real pesquisado mudaria conforme você altera o diretório de trabalho atual).
  4. Adicionando um caminho que já está PATHem uma forma diferente (por exemplo, um alias devido ao uso de links simbólicos ou ..).
  5. Se você evitar fazer 4, não mova o caminho para a frente PATHquando se pretende substituir outras entradas PATH.

Essa função (somente Bash) faz a "coisa certa" nas situações acima (com uma exceção, veja abaixo), retorna códigos de erro e imprime boas mensagens para humanos. Os códigos e mensagens de erro podem ser desativados quando não são desejados.

prepath() {
    local usage="\
Usage: prepath [-f] [-n] [-q] DIR
  -f Force dir to front of path even if already in path
  -n Nonexistent dirs do not return error status
  -q Quiet mode"

    local tofront=false errcode=1 qecho=echo
    while true; do case "$1" in
        -f)     tofront=true;       shift;;
        -n)     errcode=0;          shift;;
        -q)     qecho=':';          shift;;
        *)      break;;
    esac; done
    # Bad params always produce message and error code
    [[ -z $1 ]] && { echo 1>&2 "$usage"; return 1; }

    [[ -d $1 ]] || { $qecho 1>&2 "$1 is not a directory."; return $errcode; }
    dir="$(command cd "$1"; pwd -P)"
    if [[ :$PATH: =~ :$dir: ]]; then
        $tofront || { $qecho 1>&2 "$dir already in path."; return 0; }
        PATH="${PATH#$dir:}"        # remove if at start
        PATH="${PATH%:$dir}"        # remove if at end
        PATH="${PATH//:$dir:/:}"    # remove if in middle
    fi
    PATH="$dir:$PATH"
}

A exceção é que essa função não canoniza caminhos adicionados PATHpor outros meios, portanto, se um alias não canônico de um caminho estiver inserido PATH, isso adicionará uma duplicata. Tentar canonizar caminhos já existentes PATHé uma proposição arriscada, pois um caminho relativo tem um significado óbvio quando passado para, prepathmas quando já está no caminho, você não sabe qual era o diretório de trabalho atual quando foi adicionado.


com relação aos caminhos relativos: que tal ter uma opção '-r', que adicionaria o caminho sem torná-lo absoluto primeiro e que também o procuraria como absoluto antes de adicioná-lo? Se este fosse um script, poderia-se usá-lo em outras conchas. Existe algum benefício em tê-lo como uma função? código legal!
hoijui 10/06

1
@hoijui Tem que ser uma função porque está modificando o ambiente atual. Se fosse um script, modificaria o ambiente do subprocesso executando o script e, quando o script saísse, você teria o mesmo de $PATHantes. Quanto a -r, não, acho que caminhos relativos $PATHsão pouco confiáveis ​​e estranhos (seu caminho muda toda vez que você cd!) Para oferecer suporte a algo assim em uma ferramenta geral.
Curt J. Sampson

5

Para mim (no Mac OS X 10.9.5), adicionar o nome do caminho (por exemplo /mypathname) ao arquivo /etc/pathsfuncionou muito bem.

Antes de editar, echo $PATHretorna:

/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin

Após editar /etc/pathse reiniciar o shell, a variável $ PATH é anexada /pathname. De fato, echo $PATHretorna:

/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/mypathname

O que aconteceu é que /mypathnamefoi anexado à $PATHvariável.


3
É melhor adicionar um arquivo ao diretório /etc/paths.d do que editar o próprio arquivo / etc / caminhos.
Rbrewer

4

Para adicionar um novo caminho à PATHvariável de ambiente:

export PATH=$PATH:/new-path/

Para que essa alteração seja aplicada a todos os shell que você abrir, adicione-o ao arquivo que o shell fornecerá quando for chamado. Em conchas diferentes, isso pode ser:

  • Bash Shell: ~ / .bash_profile, ~ / .bashrc ou perfil
  • Korn Shell: ~ / .kshrc ou .profile
  • Shell Z: ~ / .zshrc ou .zprofile

por exemplo

# export PATH=$PATH:/root/learning/bin/
# source ~/.bashrc
# echo $PATH

Você pode ver o caminho fornecido na saída acima.


4

Aqui está a minha solução:

PATH=$(echo -n $PATH | awk -v RS=: -v ORS=: '!x[$0]++' | sed "s/\(.*\).\{1\}/\1/")

Um forro fácil e agradável que não deixa rastro :


1
-bash: awk: Nenhum tal lima ou diretório -bash: sed: Nenhum tal lima ou diretório
davidcondrey

1
@davidcondrey - awk e sed são comandos externos muito comuns. Esta resposta fornece uma maneira pura festa de alcançar o mesmo, por isso funciona mesmo nos casos em awk e / ou sed não estão presentes (ou seus respectivos diretórios não estão no caminho!)
sancho.s
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.