Gerando comandos com expansão variável em loop

Gerando comandos com expansão variável em loop

Quero criar aliases locais enquanto trabalho em determinados diretórios. Por exemplo, eu gostaria de ter o seguinte em um arquivo chamadolocal_alias

alias foo='bar'

Eu queria escrever um script de limpeza para remover esses aliases depois de terminar de trabalhar. Algo como:

egrep "alias [[:alnum:]]+" local_alias -o|while read i; do
  un$i
done

Se eu alterar a linha do meio para echo un$i, a saída será o que parece ser um unaliascomando formatado corretamente: unalias foo. Mas como está escrito, eu entendo unalias: foo: not found.

Se eu tentar citar a linha do meio: "un$i", recebo unalias foo: command not found.

O que estou fazendo de errado?

Responder1

Os aliases são específicos do shell, portanto, quando você executa seu script assim:

#!/bin/bash

...
unalias ....
...

Ele está sendo executado como um shell filho, que normalmente não terá os mesmos aliases. Para agravar o problema, você também está lidando com outro problema. Assim que o script termina, o shell filho cujos aliases foram removidos desaparece, retornando você ao shell pai que ainda tem seus aliases intactos.

Não há nenhuma maneira que eu saiba de que os aliases do seu shell atual sejam modificados dessa maneira.

Então como fazer isso?

Você pode construir um alias ou uma função dentro do escopo do próprio shell atual para executar esta ação.

Exemplo

solução de alias

$ alias unalias_local='egrep "alias [[:alnum:]]+" local_alias -o|while read i; do un$i; done'

solução de função

$ function unalias_local { egrep "alias [[:alnum:]]+" local_alias -o | \
    while read i; do un$i; done; }

Problemas com o acima

O OP forneceu estas soluções para esta resposta que, segundo ele, funcionarão em seu cenário. Mas, em geral, você não pode alterar os aliases em uma cadeia de comandos canalizados como esse porque cada canal invoca um subshell, que não poderá tocar no shell pai. Então voltamos ao mesmo problema anterior com o script.

Para contornar isso, você poderia fornecer a lista de aliases como argumentos para um comando.

Exemplo

$ alias ali1="cmd1"
$ alias ali2="cmd2"

Confirme os aliases em nosso shell:

$ alias | grep -E "ali[12]"
alias ali1='cmd1'
alias ali2='cmd2'

Conteúdo de local_alias:

$ cat local_alias 
alias ali1="cmd1"
alias ali2="cmd2"

Este comando irá analisar os nomes dos aliases do arquivo local_alias:

$ grep -oP "(?<=alias )([[:alnum:]]+)" local_alias
ali1
ali2

Podemos usá-lo para unaliasestes aliases da seguinte forma:

$ unalias $(grep -oP "(?<=alias )([[:alnum:]]+)" local_alias)
$

Agora, quando confirmarmos que eles se foram:

$ alias | grep -E "ali[12]"
$

Responder2

Parece que você está executando esse código em um script separado. Isso não funciona: você precisa alterar a configuração do seu shell em execução e não pode fazer isso em outro processo. Este código de limpeza deve estar em uma função definida no seu arquivo .bashrc.

Um segundo problema é que o pipe também cria um subprocesso (um subshell). Portanto, se você executar esse código dentro do seu shell interativo, o unaliascomando removerá o alias — mas apenas no subshell. Você precisa de uma abordagem diferente que não execute o unaliascomando em um subshell.

Existem várias soluções, mas a mais simples seria construir a lista de aliases e depois executar o unaliascomando uma vez. Os nomes de alias não podem conter caracteres especiais, portanto, a divisão de palavras na lista de alias será suficiente para gerar os argumentos para unalias.

unalias $(egrep -o "alias [[:alnum:]]+" local_alias)

informação relacionada