aliases do bash não se expandem mesmo com shopt expand_aliases

8

Eu quero executar um alias dentro de uma bash -cconstrução.

O bashmanual diz:

Os aliases não são expandidos quando o shell não é interativo, a menos que a expand_aliasesopção do shell seja configurada usandoshopt

Neste exemplo, por que o alias hinão foi encontrado ao definir expand_aliasesexplicitamente?

% 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

Estou correndo GNU bash, version 5.0.0(1)-release (x86_64-pc-linux-gnu).

Contexto: desejo poder executar um alias com prioridade ociosa, por exemplo, um script que contenha:

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

Quero evitar o uso, bash -ipois não quero que meu .bashrcseja lido.

Tom Hale
fonte
3
O parágrafo logo após a declaração citada no manual do Bash parece cobrir isso: '... Os aliases são expandidos quando um comando é lido, não quando é executado. Portanto, uma definição de alias que aparece na mesma linha que outro comando não entra em vigor até que a próxima linha de entrada seja lida. Os comandos que seguem a definição de alias nessa linha não são afetados pelo novo alias ... ''
Haxiel 22/02/19
Como na maioria dos casos, você deve considerar o uso de uma função shell em vez de um alias aqui. bash -c "hi () { echo hello; }; hi"saídas hello.
chepner 22/02/19

Respostas:

16

Não parece funcionar se você definir o alias na mesma linha usada. Provavelmente, algo a ver com a forma como os aliases são expandidos muito cedo no processamento da linha de comandos, antes do estágio de análise real. Em um shell interativo:

$ 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 como o alias usado está atrasado em uma linha: no segundo comando, ele não encontra o alias definido, e no terceiro comando, ele usa o que foi definido anteriormente.

Então, funciona se colocarmos uma nova linha dentro da -cstring:

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

(Você também pode usar em bash -O expand_aliases -c ...vez de usar shoptno script, não que isso ajude com a nova linha.)

Como alternativa, você pode usar uma função shell em vez de um pseudônimo, eles são muito melhores de outras maneiras também:

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

Transformando meu comentário em uma resposta, conforme sugerido por ilkkachu.

O manual do Bash (vinculado à pergunta) fornece uma explicação de como os aliases são manipulados quando há uma definição de alias e um comando na mesma linha.

Quote (ligeiramente formatado para maior clareza):

As regras relativas à definição e uso de aliases são um tanto confusas. O Bash sempre lê pelo menos uma linha completa de entrada e todas as linhas que compõem um comando composto antes de executar qualquer um dos comandos nessa linha ou no comando composto.

Os aliases são expandidos quando um comando é lido, não quando é executado. Portanto, uma definição de alias que aparece na mesma linha que outro comando não entra em vigor até que a próxima linha de entrada seja lida. Os comandos que seguem a definição de alias nessa linha não são afetados pelo novo alias.

Esse comportamento também é um problema quando as funções são executadas. Os aliases são expandidos quando uma definição de função é lida, não quando a função é executada, porque uma definição de função é ela mesma um comando. Como conseqüência, os aliases definidos em uma função não estarão disponíveis até depois que a função for executada.

Para estar seguro, sempre coloque definições de alias em uma linha separada e não use alias em comandos compostos.

A resposta de ilkkachu fornece várias soluções possíveis para esse problema.

Haxiel
fonte
FWIW, vi seu último comentário, mas não tive tempo de responder. Não é ruim que as respostas complementem outras pessoas, e saber que é realmente documentado dessa maneira é útil. Então, obrigado por escrever isso, agora eu posso votar novamente. :)
ilkkachu 22/02/19