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 -c
una 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 foo
está 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 myalias
ayudar?
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 ONESHOT
o 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 while
bucle se ejecutará por líneas, manejando una línea en un bucle. Después de leer myalias
la última línea del comando (ver arriba), la condición while
se volverá falsa. myalias
se 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 myalias
de leer myalias
, la condición while
seguirá siendo verdadera, por lo que los otros dos eco tendrán la oportunidad de ejecutarse en el siguiente bucle. La última línea posterior myalias
se manejará después de que myalias
se 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.