Bash: ¿Por qué se ignora el alias después de la nueva línea cuando se ejecuta de forma remota?

Bash: ¿Por qué se ignora el alias después de la nueva línea cuando se ejecuta de forma remota?

En Bash ejecuto:

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

que devuelve:

foo
bar
baz

Pero:

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

Devoluciones:

foo

¿Por qué?

Respuesta1

Creo que encontraste un error de Bash. Este error es específico de la opción -c.

La ejecución remota no tiene nada que ver con el problema del alias multilínea. Puedes probarlo en tu fiesta local. Pero no en bash script o bash interactivo, pruébelo con -cuna opción como esta

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

El mismo resultado que su problema. Sólo fooestá impreso.

Para obtener el resultado correcto (esperado), debe agregar al menos una línea más después myalias, como sugirió @cuonglm.

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

¿Por qué sucedería de esta manera? ¿Por qué una línea más después de myaliasayudar?

Sólo quiero decir que esto no tiene sentido. Ningún documento en Bash explica o menciona este caso, ni un poquito. Se supone que no debe funcionar de esta manera. Esto es un error. Después de leer el código, estará seguro de este punto.

Vuelva al primer comando problemático. Esta vez no cambies nada, solo vuelve a compilar bash.con "ONESHOT" indefinido, entonces obtendrá el resultado correcto (esperado). Sí, has oído bien, el comando tiene dos comportamientos diferentes simplemente debido a la diferente configuración en tiempo de compilación.

Definir ONESHOTo no conducirá a dos rutas completamente diferentes en el código Bash para -c "command". Si no se define ONESHOT, -c "command"se ejecutará la ruta de código normal, que es la ruta de código para casi todas las ejecuciones de bash, como el comando interactivo y el script de bash. Pero si define ONESHOT, -c "command"ejecutará otra ruta particular que está especialmente diseñada solo para él, para mejorar su rendimiento evitando la bifurcación.

En este caso, la forma normal y más utilizada puede dar el resultado correcto, mientras que la forma particular no. Creo que el comportamiento inconsistente no es lo que quieren los autores de Bash. En cuanto a qué comportamiento es correcto, tiendo a pensar que la forma normal es la correcta.

Algunos detalles sobre este error.

El siguiente fragmento de código está relacionado con el error. Es de la función parse_and_execute() en el archivo incorporado/evalstring.c

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

Este whilebucle se ejecutará por líneas, manejando una línea en un bucle. Después de leer myaliasla última línea del comando (ver arriba), la condición whilese volverá falsa. myaliasse expande a tres líneas de eco, pero solo se maneja un eco en este bucle; los otros dos ecos se manejarán en el siguiente bucle, pero... no hay otro bucle.

Si agrega una línea más después myaliasde leer myalias, la condición whileseguirá siendo verdadera, por lo que los otros dos eco tendrán la oportunidad de ejecutarse en el siguiente bucle. La última línea posterior myaliasse manejará después de que myaliasse manejen todos los ecos expandidos.

ACTUALIZAR

Olvidé decir la versión de Bash involucrada en este problema, que es

GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu)

Respuesta2

Solución alternativa (inspirada en @cuonglm):

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

Esto preservará el código de salida. El true, sin embargo,debeestar en una nueva línea.

Todavía no explica por qué. Pero cada vez parece más un error.

información relacionada