Ou, de forma mais geral, como removo um item de uma lista separada por dois pontos em uma variável de ambiente Bash?
Eu pensei ter visto uma maneira simples de fazer isso anos atrás, usando as formas mais avançadas de expansão de variável Bash, mas se foi, perdi o controle. Uma busca rápida no Google encontrou surpreendentemente poucos resultados relevantes e nenhum que eu chamaria de "simples" ou "elegante". Por exemplo, dois métodos usando sed e awk, respectivamente:
PATH=$(echo $PATH | sed -e 's;:\?/home/user/bin;;' -e 's;/home/user/bin:\?;;')
PATH=!(awk -F: '{for(i=1;i<=NF;i++){if(!($i in a)){a[$i];printf s$i;s=":"}}}'<<<$PATH)
Não existe nada simples? Existe algo análogo a uma função split () no Bash?
Atualizar:
Parece que preciso me desculpar por minha pergunta intencionalmente vaga; Eu estava menos interessado em resolver um caso de uso específico do que em provocar uma boa discussão. Felizmente, consegui!
Existem algumas técnicas muito inteligentes aqui. No final, adicionei as três funções a seguir à minha caixa de ferramentas. A mágica acontece em path_remove, que é amplamente baseado no uso inteligente de Martin York da awk
variável RS.
path_append () { path_remove $1; export PATH="$PATH:$1"; }
path_prepend () { path_remove $1; export PATH="$1:$PATH"; }
path_remove () { export PATH=`echo -n $PATH | awk -v RS=: -v ORS=: '$0 != "'$1'"' | sed 's/:$//'`; }
O único problema real é o uso de sed
para remover os dois pontos à direita. Considerando o quão simples é o resto da solução de Martin, estou bastante disposto a viver com isso!
Questão relacionada: Como posso manipular elementos $ PATH em scripts de shell?
fonte
WORK=`echo -n ${1} | awk -v RS=: -v ORS=: '$0 != "'${3}'"' | sed 's/:$//'`; eval "export ${2}=${WORK}"
mas você deve chamá-la comofunc $VAR VAR pattern
(com base em @ martin-york e @andrew-aylett)Respostas:
Um minuto com awk:
Editar: É resposta aos comentários abaixo:
Editar em resposta ao problema de segurança: (isso não é relevante para a pergunta)
Isso remove quaisquer dois pontos finais deixados, excluindo as últimas entradas, o que adicionaria efetivamente
.
ao seu caminho.fonte
PATH
variável faz , como uma regra especial, denotam diretório atual em todas as conchas Unix desde pelo menos V7 Unix de 1979. Ele ainda faz embash
. Verifique o manual ou experimente você mesmo.Meu hack sujo:
fonte
Já que o grande problema com a substituição são os casos finais, que tal fazer com que os casos finais não sejam diferentes dos outros casos? Se o caminho já tivesse dois pontos no início e no final, poderíamos simplesmente pesquisar nossa string desejada envolta em dois pontos. Do jeito que está, podemos facilmente adicionar esses dois pontos e removê-los depois.
Bash puro :).
fonte
WORK
ePATH
como a expansão da variável acontece depois que a linha é analisada em seções para atribuição de variável e execução de comando.REMOVE
pode precisar ser citado, ou você pode simplesmente colocar sua string diretamente na substituição, se for uma constante.Esta é a solução mais simples que posso conceber:
O exemplo acima removerá qualquer elemento em $ PATH que contenha "usr". Você pode substituir "* usr *" por "/ home / user / bin" para remover apenas esse elemento.
atualizar por sschuberth
Mesmo que eu ache que os espaços em um
$PATH
são uma ideia horrível , aqui está uma solução que dá conta disso:ou
fonte
Aqui está um one-liner que, apesar das respostas aceitas e de maior pontuação , não adiciona caracteres invisíveis ao PATH e pode lidar com caminhos que contêm espaços:
Pessoalmente, também acho isso fácil de ler / entender e envolve apenas comandos comuns em vez de usar o awk.
fonte
export PATH=$(p=$(echo $PATH | tr ":" "\0" | grep -v -z "/cygwin/" | tr "\0" ":"); echo ${p%:})
(embora sem dúvida, você pode querer se perguntar por que precisa disso, se precisar :))grep -v "^/path/to/remove\$"
ougrep -v -x "/path/to/remove"
tr
é mais comum do queawk
? ;)tr
vez de um interpretadorawk
.echo "..."
porprintf "%s" "..."
para que funcione em caminhos semelhantes-e
e semelhantes. Consulte stackoverflow.com/a/49418406/102441Aqui está uma solução que:
IFS
,remove todas as ocorrências do argumento em
PATH
.fonte
Desenterrei do meu arquivo .bashrc. Quando você brinca com o PATH e ele se perde, awk / sed / grep fica indisponível :-)
fonte
A melhor opção de bash puro que encontrei até agora é a seguinte:
Isso se baseia na resposta incorreta de Adicionar diretório a $ PATH se ainda não estiver lá no Superusuário.
fonte
removePath () { PATH=${PATH/":$1"/}; PATH=${PATH/"$1:"/}; }
$PATH
contém uma subpasta do caminho de destino (ou seja, a ser excluído). Por exemplo:a:abc/def/bin:b
->a/bin:b
, quandoabc/def
deve ser excluído.Acabei de usar as funções da distribuição bash, que aparentemente existem desde 1991. Ainda estão no pacote bash-docs no Fedora e costumavam ser usadas
/etc/profile
, mas não mais ...fonte
Eu escrevi uma resposta para isso aqui (usando awk também). Mas não tenho certeza de que é isso que você está procurando. Parece pelo menos claro para mim o que faz, em vez de tentar encaixar em uma linha. Para um liner simples, porém, que só remove coisas, eu recomendo
Substituir é
ou (mais curto, mas menos legível)
De qualquer forma, para a mesma pergunta, e muitas respostas úteis, veja aqui .
fonte
awk '$0 !~ "/bin"'
. Ou seja, mantém as linhas que não contêm '/ bin' com o operador awk!~
.Bem, no bash, como ele suporta expressão regular, eu simplesmente faria:
fonte
Eu gosto das três funções mostradas na atualização do @BenBlank para sua pergunta original. Para generalizá-los, eu uso uma forma de 2 argumentos, que me permite definir PATH ou qualquer outra variável de ambiente que eu quiser:
Exemplos de uso:
Observe que também adicionei algumas aspas para permitir o processamento adequado de nomes de caminhos que contenham espaços.
fonte
O que é mais elegante do que awk?
Pitão! É uma solução mais legível e sustentável e é fácil inspecionar para ver se ela está realmente fazendo o que você deseja.
Digamos que você queira remover o primeiro elemento do caminho?
(Em vez de canalizar de
echo
,os.getenv['PATH']
seria um pouco mais curto e forneceria o mesmo resultado que o acima, mas estou preocupado que Python possa fazer algo com essa variável de ambiente, então é provavelmente melhor canalizá-la diretamente do ambiente que você considera .)Da mesma forma para remover do final:
Para tornar essas funções de shell reutilizáveis que você pode, por exemplo, manter em seu arquivo .bashrc:
fonte
Sim, colocar dois pontos no final de PATH, por exemplo, torna a remoção de um caminho um pouco menos desajeitada e sujeita a erros.
fonte
Se você está preocupado em remover duplicatas em $ PATH, a maneira mais elegante, IMHO, seria não adicioná-las em primeiro lugar. Em 1 linha:
$ pasta pode ser substituída por qualquer coisa e pode conter espaços ("/ home / usuário / meus documentos")
fonte
A solução bash pura mais elegante que encontrei até hoje:
fonte
A maioria das outras soluções sugeridas contar apenas com strings e não levam em conta os segmentos de caminho contendo nomes especiais como
.
,..
ou~
. A função bash abaixo resolve strings de diretório em seu argumento e em segmentos de caminho para encontrar correspondências lógicas de diretório, bem como correspondências de string.Teste:
fonte
Linux from Scratch define três funções Bash em
/etc/profile
:Ref: http://www.linuxfromscratch.org/blfs/view/svn/postlfs/profile.html
fonte
Eu sei que esta pergunta é sobre BASH, que todos deveriam preferir, mas como eu gosto de simetria e às vezes sou obrigado a usar "csh", construí o equivalente a "path_prepend ()", "path_append ()" e "path_remove () "solução elegante acima.
A essência é que "csh" não tem funções, então coloquei pequenos scripts de shell em meu diretório bin pessoal que agem como as funções. Eu crio aliases para SOURCE esses scripts para fazer as alterações de variáveis de ambiente designadas.
~ / bin / _path_remove.csh:
~ / bin / _path_append.csh:
~ / bin / _path_prepend.csh:
~ / bin / .cshrc:
Você pode usá-los assim ...
fonte
Uma vez que isso tende a ser bastante problemático, já que NÃO EXISTE uma maneira elegante, recomendo evitar o problema reorganizando a solução: construa seu PATH em vez de tentar derrubá-lo.
Eu poderia ser mais específico se soubesse o contexto do seu problema real. Nesse ínterim, usarei uma construção de software como contexto.
Um problema comum com compilações de software é que ele quebra em algumas máquinas, principalmente devido a como alguém configurou seu shell padrão (PATH e outras variáveis de ambiente). A solução elegante é tornar seus scripts de construção imunes especificando totalmente o ambiente de shell. Codifique seus scripts de construção para definir o PATH e outras variáveis de ambiente com base em peças de montagem que você controla, como a localização do compilador, bibliotecas, ferramentas, componentes, etc. Torne cada item configurável algo que você possa definir, verificar e em seguida, use apropriadamente em seu script.
Por exemplo, eu tenho um build Java baseado em Maven WebLogic que herdei do meu novo empregador. O script de construção é conhecido por ser frágil, e outro novo funcionário e eu passamos três semanas (não em tempo integral, apenas aqui e ali, mas ainda muitas horas) fazendo-o funcionar em nossas máquinas. Uma etapa essencial foi assumir o controle do PATH para saber exatamente qual Java, qual Maven e qual WebLogic estava sendo invocado. Eu criei variáveis de ambiente para apontar para cada uma dessas ferramentas, então calculei o PATH com base nessas e em algumas outras. Técnicas semelhantes domesticaram as outras configurações configuráveis, até que finalmente criamos uma compilação reproduzível.
A propósito, não use o Maven, Java é bom, e só compre o WebLogic se você realmente precisar de seu clustering (mas de outra forma não, e especialmente de seus recursos proprietários).
Muitas felicidades.
fonte
PATH
. Claro, você pode criar seu próprio, mas toda vez que seu administrador move algo, você precisa descobrir onde ele o colocou. Isso acaba com o propósito de ter um administrador.Assim como com @litb, eu contribuí com uma resposta para a pergunta " Como faço para manipular elementos $ PATH em scripts de shell ", portanto, minha resposta principal está lá.
A funcionalidade de 'divisão' em
bash
e em outros derivados do Bourne shell é mais facilmente obtida com$IFS
o separador entre campos. Por exemplo, para definir os argumentos posicionais ($1
,$2
, ...) para os elementos da PATH, use:Funcionará bem desde que não haja espaços em $ PATH. Fazê-lo funcionar para elementos de caminho contendo espaços é um exercício não trivial - deixado para o leitor interessado. Provavelmente, é mais simples lidar com isso usando uma linguagem de script como Perl.
Eu também tenho um script,
clnpath
que uso extensivamente para definir meu PATH. Documentei na resposta a " Como evitar a duplicação da variável PATH no csh ".fonte
O que torna esse problema irritante são os casos de postes de cerca entre o primeiro e o último elemento. O problema pode ser resolvido elegantemente alterando o IFS e usando um array, mas não sei como reintroduzir os dois pontos depois que o caminho é convertido para a forma de array.
Aqui está uma versão um pouco menos elegante que remove um diretório do
$PATH
uso apenas da manipulação de strings. Eu testei.fonte
Aqui está um one-liner Perl:
A
$a
variável obtém o caminho a ser removido. Os comandoss
(substituto) eprint
operam implicitamente na$_
variável.fonte
Coisas boas aqui. Eu uso este para evitar adicionar ingênuos em primeiro lugar.
fonte
case ":$PATH:" in (*:"$nodup":*) ;; (*) PATH="$PATH:$nodup" ;; esac
Com o globbing estendido ativado, é possível fazer o seguinte:
fonte
One-liner de globbing estendido (bem, mais ou menos):
Parece não haver necessidade de escapar das barras em $ 1.
fonte
Adicionando dois pontos ao PATH, também podemos fazer algo como:
fonte
Em path_remove_all (por proxxy):
fonte
Embora este seja um tópico muito antigo, pensei que esta solução poderia ser do seu interesse:
encontrei nesta postagem do blog . Acho que gosto mais deste :)
fonte
Adotei uma abordagem um pouco diferente da maioria das pessoas aqui e me concentrei especificamente apenas na manipulação de cordas, assim:
A descrição acima é um exemplo simplificado das funções finais que uso. Eu também criei
path_add_before
epath_add_after
permitindo que você insira um caminho antes / depois de um caminho especificado já em PATH.O conjunto completo de funções está disponível em path_helpers.sh em meus dotfiles . Eles suportam totalmente a remoção / acréscimo / prefixação / inserção no início / meio / fim da string PATH.
fonte