псевдонимы bash не расширяются даже с shopt expand_aliases

8

Я хочу запустить псевдоним внутри bash -cконструкции.

В bashруководстве сказано:

Псевдонимы не раскрываются, когда оболочка не является интерактивной, если параметр expand_aliasesоболочки не установлен с помощьюshopt

В этом примере почему псевдоним hiне найден при expand_aliasesявной настройке ?

% 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

Я бегу GNU bash, version 5.0.0(1)-release (x86_64-pc-linux-gnu).

Контекст: я хочу иметь возможность запускать псевдоним с приоритетом ожидания, например, скрипт, содержащий:

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

Я хочу избежать использования, bash -iпоскольку я не хочу, чтобы мои .bashrcчитали.

Том Хейл
источник
3
Параграф сразу после цитируемого утверждения из руководства Bash, кажется, охватывает это: «... Псевдонимы раскрываются при чтении команды, а не при ее выполнении. Поэтому определение псевдонима, отображаемое в той же строке, что и другая команда, не вступает в силу до тех пор, пока не будет прочитана следующая строка ввода. Команды, следующие за определением псевдонима в этой строке, не зависят от нового псевдонима ... '
Хаксиэль
Как и в большинстве случаев, вам следует рассмотреть возможность использования функции оболочки вместо псевдонима. bash -c "hi () { echo hello; }; hi"выходы hello.
chepner

Ответы:

16

Это не работает, если вы устанавливаете псевдоним в той же строке, что и используемый. Возможно, это связано с тем, как псевдонимы раскрываются на самом раннем этапе обработки командной строки, до фактического этапа синтаксического анализа. На интерактивной оболочке:

$ 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

Обратите внимание, что псевдоним используется на одну строку позже: во второй команде он не находит только что установленный псевдоним, а в третьей команде он использует ранее установленный.

Итак, это работает, если мы поместим новую -cстроку в строку:

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

(Вы можете также использовать bash -O expand_aliases -c ...вместо использования shoptв скрипте, не то чтобы это помогло с новой строкой.)

В качестве альтернативы, вы можете использовать функцию оболочки вместо псевдонима, они гораздо лучше и в других отношениях:

$ bash -c 'foo() { echo foo; }; foo'
foo
ilkkachu
источник
14

Превращение моего комментария в ответ, как предложено ilkkachu.

В руководстве по Bash (связанному с вопросом) дается объяснение того, как обрабатываются псевдонимы, когда в одной строке есть определение псевдонима и команда.

Цитата (слегка отформатирована для ясности):

Правила, касающиеся определения и использования псевдонимов, несколько сбивают с толку. Bash всегда читает по крайней мере одну полную строку ввода и все строки, составляющие составную команду, перед выполнением любой из команд в этой строке или составной команды.

Псевдонимы раскрываются при чтении команды, а не при ее выполнении. Поэтому определение псевдонима, отображаемое в той же строке, что и другая команда, не вступает в силу до тех пор, пока не будет прочитана следующая строка ввода. На команды, следующие за определением псевдонима в этой строке, новый псевдоним не влияет.

Такое поведение также является проблемой при выполнении функций. Псевдонимы раскрываются при чтении определения функции, а не при ее выполнении, поскольку определение функции само является командой. Как следствие, псевдонимы, определенные в функции, будут недоступны до тех пор, пока эта функция не будет выполнена.

Для безопасности всегда помещайте определения псевдонимов в отдельной строке и не используйте псевдоним в составных командах.

Ответ ilkkachu дает несколько возможных решений этой проблемы.

Haxiel
источник
FWIW, я видел ваш последний комментарий, но не было времени, чтобы ответить. Это не плохо для ответов дополнять другие, и зная , что это на самом деле документально подтверждено , что способ является полезным. Так что спасибо, что написали это, теперь я могу выразить это. :)
ilkkachu