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 que?
Responder1
Acho que você encontrou um bug do Bash. Este bug é específico da 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 experimentá-lo em sua festa local. Mas não no script bash ou no bash interativo, tente com -c
a opção, 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. Somente foo
é impresso.
Para obter a saída correta (esperada), você deve adicionar pelo menos mais uma linha depois myalias
, como sugerido por @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 depois da myalias
ajuda?
Só quero dizer que isso não faz sentido. Nenhum documento no Bash explica ou menciona este caso, nem um pouco. Não é suposto funcionar desta forma. Isso é um bug. Depois de ler o código, você terá certeza disso.
Volte para o primeiro comando problemático. Desta vez não mude nada, apenas recompile o bashcom "ONESHOT" indefinido, então você obterá a saída correta (esperada). Sim, você ouviu direito, o comando tem dois comportamentos diferentes apenas por causa de diferentes configurações de tempo de compilação.
Definir ONESHOT
ou não levará a duas rotas completamente diferentes no código Bash para -c "command"
. Se indefinido, ONESHOT -c "command"
executará a rota de código normal, que é a rota de código para quase todas as execuções do bash, como comando interativo e script bash. Mas se definir ONESHOT, -c "command"
irá executar outra rota específica que é especialmente desenhada apenas para ele, para melhorar seu desempenho evitando bifurcação.
Nesse caso, a forma normal e mais usada pode fornecer o resultado correto, enquanto a forma específica não. Acho que o comportamento inconsistente não é o que os autores do Bash desejam. Quanto a qual comportamento é correto, tendo a pensar que o comportamento normal é correto.
Alguns detalhes sobre esse bug
O trecho de código a seguir está relacionado ao bug. É da função parse_and_execute() no arquivo builtins/evalstring.c
while (*(bash_input.location.string))
{
...
}
Este while
loop será executado por linhas, manipulando uma linha em um loop. Após read myalias
, a última linha, no comando (veja acima), a condição in while
se tornará falsa. myalias
é expandido para três linhas de eco, mas apenas um eco é tratado neste loop; os outros dois ecos serão tratados no próximo loop, mas... não há outro loop.
Se você adicionar mais uma linha myalias
depois de read myalias
, a condição while
permanecerá verdadeira, então os outros dois echo terão a chance de executar no próximo loop. A última linha após myalias
será tratada depois que todos os ecos expandidos forem myalias
tratados.
ATUALIZAR
Esqueci de dizer a versão do Bash envolvida neste problema, que é
GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu)
Responder2
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,deveestar em uma nova linha.
Ainda não explica o porquê. Mas cada vez mais parece um bug.