Uma maneira mais confortável de editar um longo $ PATH?


35

Quero adicionar, em ~ / .bashrc, alguns diretórios ao meu $ PATH.

Meu $ PATH é bastante longo, portanto é um pouco difícil ver quais diretórios ele contém e em que ordem.

Eu sei que posso modificar meu ~ / .bashrc para:

PATH=$PATH:/some/dir
PATH=$PATH:/another/dir:/yet/another
PATH=$PATH:/and/another
...

facilitaria a leitura. Mas eu queria saber se, durante os últimos anos, o Bash adquiriu alguma sintaxe que facilita a especificação de um longo caminho. Por exemplo, estou fantasiando sobre uma sintaxe semelhante a:

PATH=:((
  /some/dir
  /another/dir
  /yet/another
  /and/another
  ...
))

Eu sei que essa sintaxe é inválida. Fiquei me perguntando se há algo tão fácil. Existe?


O tutorial tradicional para definir o caminho via PATH=foo:$PATHparece errado porque manter o crescimento cada vez source ~/.bashrce até mesmo exec bashnão pode ajudar, uma vez que o $PATHé export.
林果 皞

Respostas:


25

Eu uso um conjunto de funções de conveniência para acrescentar ou acrescentar um caminho a uma variável. As funções vêm no pacote de distribuição do Bash em um arquivo de contribuição chamado "pathfuncs".

  • add_path adicionará a entrada ao final da variável PATH
  • pre_path adicionará a entrada ao início da variável PATH
  • del_path removerá a entrada da variável PATH, onde quer que esteja

Se você especificar uma variável como o segundo argumento, ela será usada em vez de PATH.

Por conveniência, aqui estão eles:

# is $1 missing from $2 (or PATH) ?
no_path() {
    eval "case :\$${2-PATH}: in *:$1:*) return 1;; *) return 0;; esac"
}
# if $1 exists and is not in path, append it
add_path () {
  [ -d ${1:-.} ] && no_path $* && eval ${2:-PATH}="\$${2:-PATH}:$1"
}
# if $1 exists and is not in path, prepend it
pre_path () {
  [ -d ${1:-.} ] && no_path $* && eval ${2:-PATH}="$1:\$${2:-PATH}"
}
# if $1 is in path, remove it
del_path () {
  no_path $* || eval ${2:-PATH}=`eval echo :'$'${2:-PATH}: |
    sed -e "s;:$1:;:;g" -e "s;^:;;" -e "s;:\$;;"`
}

Se você os adicionar ao seu arquivo de inicialização do bash, poderá adicioná-lo ao PATH assim:

pre_path $HOME/bin
add_path /sbin
add_path /usr/sbin

Ou especifique uma variável diferente:

pre_path $HOME/man MANPATH
pre_path $HOME/share/man MANPATH
add_path /usr/local/man MANPATH
add_path /usr/share/man MANPATH

Eu uso esse método nos meus arquivos rc colocando os pre_paths primeiro e os add_paths segundo. Isso facilita a compreensão de todas as alterações no meu caminho. Outro benefício é que as linhas são curtas o suficiente para que eu possa adicionar um comentário à linha, se necessário.

E como essas são funções, você pode usá-las interativamente a partir da linha de comando, como dizendo add_path $(pwd)para adicionar o diretório atual ao caminho.


Obrigado. Eu verifiquei seu código e ele funciona. Surpreendentemente, eu também encontrei um uso para del_path (A "." Entra em meu PATH em algumas situações, o diabo sabe de onde, então eu fiz del_path .).
Nicolau M.

Oi. é possível originar (incluir) esses caminhos do script bashrc ou devo copiá-los / colá-los para lá?
Cristiano

@Cristiano Ou vai funcionar. É realmente com você.
Starfish

11

OK, descobri a seguinte solução, que acho elegante (no que diz respeito à sintaxe do shell). Ele usa a sintaxe de matriz do Bash e também uma maneira elegante de juntar elementos:

paths=(
  /some/dir
  /another/dir
  '/another/dir with spaces in it'
  /yet/another
  /and/another
  /end
)
paths_joined=$( IFS=: ; echo "${paths[*]}" )

PATH=$paths_joined:$PATH

ALERTA!

Acontece que esta solução tem um problema : Ao contrário das soluções @terdon e @Starfish, ela não verifica primeiro se os caminhos já estão no PATH. Então, como eu quero colocar esse código em ~ / .bashrc (e não em ~ / .profile), caminhos duplicados aparecerão no PATH. Portanto, não use esta solução (a menos que você a coloque em ~ / .profile (ou, melhor, ~ / .bash_profile, pois possui sintaxe específica do Bash)).


11
Muito agradável. Você pode aceitar uma resposta para que outras pessoas não venham aqui para oferecer uma solução quando você já a encontrou? Obrigado
Básico

Caminhos duplicados não são realmente um problema. É altamente improvável que você tenha adicionado diretórios suficientes PATHpara realmente causar problemas de desempenho (especialmente porque o shell armazena em cache as pesquisas bem-sucedidas).
chepner

5

Eu uso a função abaixo no meu ~/.bashrc. É algo que recebi de um administrador de sistemas no meu antigo laboratório, mas acho que ele não escreveu. Basta adicionar essas linhas ao seu ~/.profileou ~/.bashrc:

pathmunge () {
        if ! echo $PATH | /bin/grep -Eq "(^|:)$1($|:)" ; then
           if [ "$2" = "after" ] ; then
              PATH=$PATH:$1
           else
              PATH=$1:$PATH
           fi
        fi
}

Isso tem várias vantagens:

  • Adicionando novos diretórios para o $PATHtrivial: pathmunge /foo/bar;
  • Evita entradas duplicadas;
  • Você pode optar por adicionar uma nova entrada ao início ( pathmunge /foo/barou ao final ( pathmunge /foo/bardepois) do) $PATH.

O arquivo de inicialização do seu shell conteria algo como:

pathmunge /some/dir
pathmunge /another/dir
pathmunge '/another/dir with spaces in it'
pathmunge /yet/another
pathmunge /and/another
pathmunge /end

Obrigado. Mas vou escolher a solução da @ Starfish porque a dele não aparece grep.
Nicolau M.

2
@NiccoloM. não tem problema, aceite qual você preferir. Porém, tenha cuidado com a abordagem da estrela do mar, pois ela executará código arbitrário através do evalcomando para que você possa causar algum dano sério se o executar com o argumento errado.
terdon

Observe que existe uma função mais rápida no redhat para fazer isso sem comando externo grep, consulte bugzilla.redhat.com/show_bug.cgi?id=544652#c7

4

Quero adicionar, em ~ / .bashrc, alguns diretórios ao meu $ PATH.

Eu uso o seguinte no Cygwin. Deve funcionar em outras versões do bash. Você pode remover a unset PATHversão atual PATH(se você fizer isso, talvez precise descobrir como adicionar os :separadores corretamente).

Nota:

  • Uma vez eu tive essa funcionalidade em uma bashfunção, mas a perdi após uma falha no disco.

No meu .bash_profile:

# Build up the path using the directories in ~/.path_elements
unset PATH
while read line; do 
  PATH="${PATH}$line"; 
done < ~/.path_elements

...

# Add current directory to path
export PATH=".:${PATH}"

Em ~/.path_elements:

/home/DavidPostill/bin:
/usr/local/bin:
/usr/bin:
/c/Windows/system32:
/c/Windows

Obrigado. Sua resposta me inspirou a trabalhar em uma solução semelhante. (Para o meu gosto armazenar os caminhos num ficheiro separado é incomodativo.)
Nicolau M.

1

Eu uso isso no meu .bashrc (e também no meu .zshrc, pois normalmente uso o zsh quando disponível, em vez do bash). É verdade que exige que eu adicione diretórios manualmente, mas uma vantagem é que, à medida que o atualizo, posso copiá-lo para novos servidores e não me preocupar com o PATH em um novo servidor criado com diretórios que não existem lá.

##
## CAMINHO
##
## Em vez de apenas atrapalhar nosso PATH com diretórios que podem
## não for apropriado para este servidor, tente ser inteligente sobre o que adicionamos
##
PATH = / usr / local / sbin: / usr / local / bin: / usr / sbin: / usr / bin: / sbin: / bin
[-d / cs / sbin] && PATH = / cs / sbin: $ PATH
[-d / cs / bin] && PATH = / cs / bin: $ PATH
[-d / usr / ucb] && PATH = $ PATH: / usr / ucb
[-d / usr / ccs / bin] && PATH = $ PATH: / usr / ccs / bin
[-d / usr / local / ssl / bin] && PATH = $ PATH: / usr / local / ssl / bin
[-d / usr / krb5 / bin] && PATH = $ PATH: / usr / krb5 / bin
[-d / usr / krb5 / sbin] && PATH = $ PATH: / usr / krb5 / sbin
[-d / usr / kerberos / sbin] && PATH = $ PATH: / usr / kerberos / sbin
[-d / usr / kerberos / bin] && PATH = $ PATH: / usr / kerberos / bin
[-d /cs/local/jdk1.5.0/bin] && PATH = $ PATH: /cs/local/jdk1.5.0/bin
[-d /usr/java/jre1.5.0_02/bin] && PATH = $ PATH: /usr/java/jre1.5.0_02/man
[-d /usr/java1.2/bin] && PATH = $ PATH: /usr/java1.2/bin
[-d /cs/local/perl5.8.0/bin] && PATH = $ PATH: /cs/local/perl5.8.0/bin
[-d / usr / perl5 / bin] && PATH = $ PATH: / usr / perl5 / bin
[-d / usr / X11R6 / bin] && PATH = $ PATH: / usr / X11R6 / bin
[-d / etc / X11] && PATH = $ PATH: / etc / X11
[-d / opt / sfw / bin] && PATH = $ PATH: / opt / sfw / bin
[-d / usr / local / apache / bin] && PATH = $ PATH: / usr / local / apache / bin
[-d / usr / apache / bin] && PATH = $ PATH: / usr / apache / bin
[-d / cs / admin / bin] && PATH = $ PATH: / cs / admin / bin
[-d / usr / openwin / bin] && PATH = $ PATH: / usr / openwin / bin
[-d / usr / xpg4 / bin] && PATH = $ PATH: / usr / xpg4 / bin
[-d / usr / dt / bin] && PATH = $ PATH: / usr / dt / bin

Eu faço o mesmo pelo meu MANPATH:

##
## MANPATH
##
## Em vez de apenas encher nosso MANPATH com diretórios que podem
## não for apropriado para este servidor, tente ser inteligente sobre o que adicionamos
##
MANPATH = / usr / local / man
[-d / usr / share / man] && MANPATH = $ MANPATH: / usr / share / man
[-d / usr / local / compartilhamento / homem] && MANPATH = $ MANPATH: / usr / local / compartilhamento / homem
[-d / usr / man] && MANPATH = $ MANPATH: / usr / man
[-d / cs / man] && MANPATH = $ MANPATH: / cs / man
[-d / usr / krb5 / man] && MANPATH = $ MANPATH: / usr / krb5 / man
[-d / usr / kerberos / man] && MANPATH = $ MANPATH: / usr / kerberos / man
[-d / usr / local / ssl / man] && MANPATH = $ MANPATH: / usr / local / ssl / man
[-d /cs/local/jdk1.5.0/man] && MANPATH = $ MANPATH: /cs/local/jdk1.5.0/man
[-d /usr/java/jre1.5.0_02/man] && MANPATH = $ MANPATH: /usr/java/jre1.5.0_02/man
[-d /usr/java1.2/man] && MANPATH = $ MANPATH: /usr/java1.2/man
[-d / usr / X11R6 / man] && MANPATH = $ MANPATH: / usr / X11R6 / man
[-d / usr / local / apache / man] && MANPATH = $ MANPATH: / usr / local / apache / man
[-d / usr / local / mysql / man] && MANPATH = $ MANPATH: / usr / local / mysql / man
[-d /cs/local/perl5.8.0/man] && MANPATH = $ MANPATH: /cs/local/perl5.8.0/man
[-d / usr / perl5 / man] && MANPATH = $ MANPATH: / usr / perl5 / man
[-d / usr / local / perl / man] && MANPATH = $ MANPATH: / usr / local / perl / man
[-d /usr/local/perl5.8.0/man] && MANPATH = $ MANPATH: /usr/local/perl5.8.0/man
[-d / usr / openwin / man] && MANPATH = $ MANPATH: / usr / openwin / man

Além de ter um único arquivo que eu posso copiar para sistemas em ambientes diferentes, sem medo de adicionar diretórios inexistentes ao PATH, essa abordagem também tem a vantagem de permitir que eu especifique a ordem em que os diretórios devem aparecer no PATH. Como a primeira linha de cada definição redefine completamente a variável PATH, eu posso atualizar meu .bashrc e originar após a edição para atualizar meu shell sem adicionar entradas duplicadas (que eu costumava experimentar há muito tempo quando simplesmente comecei com " $ PATH = $ PATH: / new / dir ". Isso garante que eu receba uma cópia limpa na ordem que desejar.


11
sugerindo uma alternativa: d="/usr/share/man" ; [ -d "$d" ] && MANPATH="$MANPATH:${d}"será mais curto e mais fácil adicionar um novo diretório (basta copiar uma linha e editar a primeira parte "d = ...."). No entanto, para o PATH, acho que você terminará com muitos dirs no PATH, o que nem sempre é bom (e se algum comando "foo" existir em um dos caminhos menos conhecidos e fazer algo totalmente diferente) que o que um usuário regular seria de esperar)?
Olivier Dulac

O OP pediu uma maneira mais concisa de adicionar caminhos. Isso é muito mais detalhado e mais propenso a erros do que o que eles já estavam tentando evitar.
underscore_d

-1

Existe uma maneira fácil! Leia Funções de Shell e Variáveis ​​de Caminho no Linux Journal , 01 de março de 2000 Por Stephen Collyer

As funções permitem-me usar um novo tipo de dados no meu ambiente bash - a lista separada por dois pontos. Além do PATH, eu os uso para ajustar meu LOCATE_PATH, MANPATH e outros, e como um tipo de dados geral na programação do bash. Aqui está como eu configuro meu PATH (usando as funções):

# Add my bin directory to $PATH at the beginning, so it overrides 
addpath -f -p PATH $HOME/bin

# For Raspberry Pi development (add at end)
addpath -b -p PATH ${HOME}/rpi/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin

# remove nonexistent directories from PATH
delpath -n -p PATH

# ensure PATH contains unique entries
uniqpath -p PATH

Como o link do Linux Journal é chamado de "quebrado", coloquei as Funções do caminho Bash em um arquivo .shar em http://pastebin.ubuntu.com/13299528/


3
Que funções são essas? Como o OP os usa? Presumivelmente, eles estão descritos no link quebrado na sua resposta, e é exatamente por isso que sempre queremos que as respostas sejam independentes. Edite e inclua as funções reais em sua resposta.
terdon

@terdon: link funciona para mim, eu coloquei um arquivo .shar em pastebin, não vou postar 1 mil linhas aqui.
waltinator

Opa, funciona para mim também agora. Não aconteceu quando deixei o comentário. De qualquer forma, a essência do meu comentário foi que tentamos evitar links para recursos externos nas respostas. Queremos que as informações estejam aqui, onde possam ser atualizadas, editadas e imunes à podridão do link.
terdon
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.