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 sobre o alias de várias linhas. Você pode experimentá-lo em seu bash local. Mas não no script bash ou no bash interativo, tente com a -copçã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. Apenas fooé impresso.
Para obter a saída correta (esperada), você deve adicionar pelo menos mais uma linha após myalias, como @cuonglm sugeriu.
bash -c "shopt -s expand_aliases &>/dev/null;
alias myalias='echo foo
echo bar
echo baz'
myalias
:"
Por que aconteceria desta forma? Por que mais uma linha depois myaliasajuda?
Só quero dizer que isso não faz sentido. Nenhum documento no Bash explica ou menciona esse caso, nem um pouco. Não é suposto funcionar desta forma. Isso é um bug. Depois de ler o código, você terá certeza desse ponto.
Volte para o primeiro comando problemático. Desta vez, não mude nada, apenas recompile o bash com "ONESHOT" undefined , então você obterá a saída correta (esperada). Sim, você ouviu bem, o comando tem dois comportamentos diferentes apenas por causa da configuração de tempo de compilação diferente.
Definir ONESHOTou não levará a duas rotas completamente diferentes no código Bash para arquivos -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 bash, como comando interativo e script bash. Mas se definir ONESHOT, -c "command"executará outra rota específica que é especialmente projetada apenas para ele, para melhorar seu desempenho evitando bifurcações.
Para este caso, a maneira normal e mais usada pode fornecer a saída correta, enquanto a maneira específica não pode. Acho que o comportamento inconsistente não é o que os autores do Bash desejam. Quanto a qual comportamento é o correto, tendo a pensar que o normal é o correto.
Alguns detalhes sobre este 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 whileloop 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 whilese 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 após myalias, após read myalias, a condição em whilepermanecerá verdadeira, então os outros dois ecos terão chance de rodar no próximo loop. A última linha depois myaliasserá tratada depois que todos os ecos expandidos por myaliasforem 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)
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 sobre o alias de várias linhas. Você pode experimentá-lo em seu bash local. Mas não no script bash ou no bash interativo, tente com a
-c
opção, como estaMesma saída do seu problema. Apenas
foo
é impresso.Para obter a saída correta (esperada), você deve adicionar pelo menos mais uma linha após
myalias
, como @cuonglm sugeriu.Por que aconteceria desta forma? Por que mais uma linha depois
myalias
ajuda?Só quero dizer que isso não faz sentido. Nenhum documento no Bash explica ou menciona esse caso, nem um pouco. Não é suposto funcionar desta forma. Isso é um bug. Depois de ler o código, você terá certeza desse ponto.
Volte para o primeiro comando problemático. Desta vez, não mude nada, apenas recompile o bash com "ONESHOT" undefined , então você obterá a saída correta (esperada). Sim, você ouviu bem, o comando tem dois comportamentos diferentes apenas por causa da configuração de tempo de compilação diferente.
Definir
ONESHOT
ou não levará a duas rotas completamente diferentes no código Bash para arquivos-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 bash, como comando interativo e script bash. Mas se definir ONESHOT,-c "command"
executará outra rota específica que é especialmente projetada apenas para ele, para melhorar seu desempenho evitando bifurcações.Para este caso, a maneira normal e mais usada pode fornecer a saída correta, enquanto a maneira específica não pode. Acho que o comportamento inconsistente não é o que os autores do Bash desejam. Quanto a qual comportamento é o correto, tendo a pensar que o normal é o correto.
Alguns detalhes sobre este bug
O trecho de código a seguir está relacionado ao bug. É da função parse_and_execute() no arquivo builtins/evalstring.c
Este
while
loop será executado por linhas, manipulando uma linha em um loop. Depois de lermyalias
, a última linha, no comando (veja acima), a condição emwhile
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 após
myalias
, após readmyalias
, a condição emwhile
permanecerá verdadeira, então os outros dois ecos terão chance de rodar no próximo loop. A última linha depoismyalias
será tratada depois que todos os ecos expandidos pormyalias
forem tratados.ATUALIZAR
Esqueci de dizer a versão do Bash envolvida neste problema, que é
Solução alternativa (inspirada em @cuonglm):
Isso preservará o código de saída. O
true
, no entanto, deve estar em uma nova linha.Ainda não explica o porquê. Mas cada vez mais parece um bug.