Bash: Por que o alias após a nova linha é ignorado quando executado remotamente?

3

No Bash eu corro:

alias myalias='echo foo
echo bar
echo baz'
myalias

que retorna:

foo
bar
baz

Mas:

ssh localhost "shopt -s expand_aliases &>/dev/null;
alias myalias='echo foo
echo bar
echo baz'
myalias"

Retorna:

foo

Por quê?

    
por Ole Tange 24.11.2017 / 00:07

2 respostas

4

Eu acho que você encontrou um bug do Bash. Este bug é específico para a opção -c .

A execução remota não tem nada a ver com o seu problema com o alias de várias linhas. Você pode tentar em sua festa local. Mas não no script bash ou no bash interativo, experimente com a opção -c , como esta

bash -c "shopt -s expand_aliases &>/dev/null;
alias myalias='echo foo
echo bar
echo baz'
myalias"

Mesma saída do seu problema. Apenas foo é impresso.

Para obter a saída correta (esperada), você precisa adicionar pelo menos mais uma linha depois de myalias , como sugerido pelo @cuonglm.

bash -c "shopt -s expand_aliases &>/dev/null;
alias myalias='echo foo
echo bar
echo baz'
myalias
:"

Por que isso aconteceria dessa maneira? Por que mais uma linha após myalias ajuda?

Eu só quero dizer que isso não faz sentido. Nenhum documento no Bash explica ou menciona este caso, nem um pouco. Não é suposto que seja executado dessa maneira. Isso é um erro. Depois de ler o código, você terá certeza deste ponto.

Volte para o primeiro comando problemático. Desta vez, não mude nada, apenas re-compile bash com "ONESHOT" indefinido , então você terá a saída certa (esperada). Sim, você ouve certo, o comando tem dois comportamentos diferentes apenas por causa da configuração diferente em tempo de compilação.

Se você definir ONESHOT ou não, haverá dois caminhos completamente diferentes no código Bash para -c "command" . Se undefine o ONESHOT, -c "command" executará a rota de código normal, que é a rota de código para quase todas as execuções bash, como o comando interativo e o script bash. Mas se definir ONESHOT, -c "command" executará outra rota específica que é especialmente projetada apenas para ela, para melhorar seu desempenho evitando garfo.

Para este caso, a maneira normal e mais usada pode dar saída certa, enquanto a maneira particular não pode. Eu acho que o comportamento inconsistente não é o que os autores do Bash querem. Quanto ao comportamento que está certo, eu costumo pensar que o caminho normal é certo.

Alguns detalhes sobre esse bug

O seguinte trecho de código está relacionado ao bug. É da função parse_and_execute () no arquivo builtins / evalstring.c

while (*(bash_input.location.string))
  {
    ...
  }

Esse loop while será executado por linhas, manipulando uma linha em um loop. Depois de ler myalias , a última linha, no comando (veja acima), a condição em while se tornará falsa. myalias é expandido para três linhas de eco, mas apenas um eco é tratado nesse loop; os outros dois ecos serão tratados no próximo loop, mas ... não há outro loop.

Se você adicionar mais uma linha após myalias , depois de ler myalias , a condição em while permanecerá verdadeira, então os dois outros eco terão chance de executar no próximo loop. A última linha após myalias será tratada depois que todos os ecos expandidos por myalias forem manipulados.

UPDATE

Esqueci de dizer a versão do Bash envolvida nesta edição, que é

GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu)
    
por 26.11.2017 / 03:30
1

Solução alternativa (inspirada em @cuonglm):

ssh localhost "shopt -s expand_aliases &>/dev/null;
alias myalias='ls
echo foo
echo bar
echo baz'
myalias &&
true"

Isso preservará o código de saída. O true , no entanto, deve estar em uma nova linha.

Ainda não explica por quê. Mas cada vez mais parece um bug.

    
por 25.11.2017 / 21:41