les alias bash ne se développent pas même avec shopt expand_aliases

8

Je veux exécuter un alias dans une bash -cconstruction.

Le bashmanuel dit:

Les alias ne sont pas développés lorsque le shell n'est pas interactif, sauf si l' expand_aliasesoption shell est définie à l'aide deshopt

Dans cet exemple, pourquoi l'alias hin'est-il pas trouvé lors de la définition expand_aliasesexplicite?

% 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

Je cours GNU bash, version 5.0.0(1)-release (x86_64-pc-linux-gnu).

Contexte: je veux pouvoir exécuter un alias à priorité inactive, par exemple un script contenant:

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

Je veux éviter d'utiliser bash -icar je ne veux pas que je .bashrcsois lu.

Tom Hale
la source
3
Le paragraphe juste après la citation du manuel Bash semble couvrir ceci: '... Les alias sont étendus lorsqu'une commande est lue, pas lorsqu'elle est exécutée. Par conséquent, une définition d'alias apparaissant sur la même ligne qu'une autre commande ne prend effet que lorsque la ligne d'entrée suivante est lue. Les commandes suivant la définition d'alias sur cette ligne ne sont pas affectées par le nouvel alias .... '
Haxiel
Comme dans la plupart des cas, vous devriez envisager d'utiliser une fonction shell au lieu d'un alias ici. bash -c "hi () { echo hello; }; hi"sorties hello.
chepner

Réponses:

16

Cela ne semble pas fonctionner si vous définissez l'alias sur la même ligne que celle utilisée. Probablement quelque chose à voir avec la façon dont les alias sont développés très tôt dans le traitement de la ligne de commande, avant l'étape d'analyse réelle. Sur un shell interactif:

$ 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

Notez que l'alias utilisé est en retard d'une ligne: sur la deuxième commande, il ne trouve pas l'alias qui vient d'être défini, et sur la troisième commande, il utilise celle qui a été précédemment définie.

Donc, cela fonctionne si nous mettons une nouvelle ligne dans la -cchaîne:

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

(Vous pouvez également utiliser bash -O expand_aliases -c ...au lieu d'utiliser shoptdans le script, pas que cela aide avec la nouvelle ligne.)

Alternativement, vous pouvez utiliser une fonction shell au lieu d'un alias, ils sont bien meilleurs à d'autres égards également:

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

Transformer mon commentaire en réponse, comme l'a suggéré ilkkachu.

Le manuel Bash (lié à dans la question) fournit une explication de la façon dont les alias sont traités lorsqu'il existe une définition d'alias et une commande sur la même ligne.

Citation (légèrement formatée pour plus de clarté):

Les règles concernant la définition et l'utilisation des alias sont quelque peu confuses. Bash lit toujours au moins une ligne d'entrée complète et toutes les lignes qui composent une commande composée, avant d'exécuter l'une des commandes sur cette ligne ou la commande composée.

Les alias sont développés lors de la lecture d'une commande et non lors de son exécution. Par conséquent, une définition d'alias apparaissant sur la même ligne qu'une autre commande ne prend effet que lorsque la ligne d'entrée suivante est lue. Les commandes suivant la définition d'alias sur cette ligne ne sont pas affectées par le nouvel alias.

Ce comportement est également un problème lorsque des fonctions sont exécutées. Les alias sont développés lors de la lecture d'une définition de fonction, pas lors de l'exécution de la fonction, car une définition de fonction est elle-même une commande. Par conséquent, les alias définis dans une fonction ne sont disponibles qu'après l'exécution de cette fonction.

Pour être sûr, placez toujours les définitions d'alias sur une ligne distincte et n'utilisez pas d'alias dans les commandes composées.

La réponse d'ilkkachu fournit plusieurs solutions possibles à ce problème.

Haxiel
la source
FWIW, j'ai vu votre dernier commentaire mais je n'ai pas eu le temps de répondre. Ce n'est pas une mauvaise chose que les réponses complètent les autres, et savoir que c'est effectivement documenté de cette façon est utile. Alors merci d'avoir écrit ceci, maintenant je peux le voter. :)
ilkkachu