los alias bash no se expanden incluso con shopt expand_aliases

8

Quiero ejecutar un alias dentro de una bash -cconstrucción.

El bashmanual dice:

Los alias no se expanden cuando el shell no es interactivo, a menos que la expand_aliasesopción del shell se establezca utilizandoshopt

En este ejemplo, ¿por qué hino se encuentra el alias cuando se configura expand_aliasesexplícitamente?

% bash -O expand_aliases -c "alias hi='echo hello'; alias; shopt expand_aliases; hi"
alias hi='echo hello'
expand_aliases  on
bash: hi: command not found

Estoy corriendo GNU bash, version 5.0.0(1)-release (x86_64-pc-linux-gnu).

Contexto: quiero poder ejecutar un alias con prioridad inactiva, por ejemplo, un script que contenga:

#!/bin/bash
exec chrt -i 0 nice -n 19 ionice -c 3 bash -c ". ~/.config/bash/aliases; shopt -s expand_aliases; $(shell-quote "$@")"

Quiero evitar el uso bash -iya que no quiero .bashrcque se lea mi .

Tom Hale
fuente
3
El párrafo justo después de la declaración citada del manual de Bash parece cubrir esto: '... Los alias se expanden cuando se lee un comando, no cuando se ejecuta. Por lo tanto, una definición de alias que aparece en la misma línea que otro comando no tiene efecto hasta que se lea la siguiente línea de entrada. Los comandos que siguen la definición de alias en esa línea no se ven afectados por el nuevo alias ... '
Haxiel
Como en la mayoría de los casos, debería considerar usar una función de shell en lugar de un alias aquí. bash -c "hi () { echo hello; }; hi"salidas hello.
chepner

Respuestas:

16

No parece funcionar si configura el alias en la misma línea que se usa. Probablemente tenga algo que ver con cómo se expanden los alias muy temprano en el procesamiento de la línea de comandos, antes de la etapa de análisis real. En un shell interactivo:

$ alias foo
bash: alias: foo: not found
$ alias foo='echo foo'; foo         # 2 
bash: foo: command not found
$ alias foo='echo bar'; foo         # 3
foo
$ foo
bar

Observe cómo el alias utilizado está retrasado una línea: en el segundo comando no encuentra el alias que acaba de establecer, y en el tercer comando usa el que se configuró previamente.

Entonces, funciona si ponemos una nueva línea dentro de la -ccadena:

$ bash -c $'shopt -s expand_aliases; alias foo="echo foo";\n foo'
foo

(También puede usar en bash -O expand_aliases -c ...lugar de usar shoptdentro del script, no es que ayude con la nueva línea).

Alternativamente, podría usar una función de shell en lugar de un alias, también son mucho mejores en otras formas:

$ bash -c 'foo() { echo foo; }; foo'
foo
ilkkachu
fuente
14

Convirtiendo mi comentario en una respuesta, como lo sugirió ilkkachu.

El manual de Bash (vinculado a la pregunta) proporciona una explicación de cómo se manejan los alias cuando hay una definición de alias y un comando en la misma línea.

Cita (ligeramente formateada para mayor claridad):

Las reglas relativas a la definición y uso de alias son algo confusas. Bash siempre lee al menos una línea de entrada completa, y todas las líneas que forman un comando compuesto, antes de ejecutar cualquiera de los comandos en esa línea o el comando compuesto.

Los alias se expanden cuando se lee un comando, no cuando se ejecuta. Por lo tanto, una definición de alias que aparece en la misma línea que otro comando no tiene efecto hasta que se lea la siguiente línea de entrada. Los comandos que siguen a la definición de alias en esa línea no se ven afectados por el nuevo alias.

Este comportamiento también es un problema cuando se ejecutan funciones. Los alias se expanden cuando se lee una definición de función, no cuando se ejecuta la función, porque una definición de función es en sí misma un comando. Como consecuencia, los alias definidos en una función no están disponibles hasta después de que se ejecuta esa función.

Para estar seguro, siempre coloque las definiciones de alias en una línea separada y no use alias en comandos compuestos.

La respuesta de ilkkachu proporciona múltiples soluciones posibles a este problema.

Haxiel
fuente
FWIW, vi tu último comentario pero no tuve tiempo de responder. No es malo que las respuestas complementen a otras, y saber que en realidad está documentado de esa manera es útil. Así que gracias por escribir esto, ahora puedo votarlo. :)
ilkkachu