Чому я не можу використовувати змінні як префікс команди для встановлення змінних середовища?


11

Зазвичай можна встановити змінну середовища для команди, префіксуючи її так:

hello=hi bash -c 'echo $hello'

Я також знаю, що ми можемо використовувати змінну для підстановки будь-якої частини виклику команди, наприклад:

$ cmd=bash
$ $cmd -c "echo hi" # equivalent to bash -c "echo hi"

Я дуже здивувався, дізнавшись, що ви не можете використовувати змінну для префіксації команди для встановлення змінної середовища. Тестовий випадок:

$ prefix=hello=hi
$ echo $prefix # prints hello=hi
$ $prefix bash -c 'echo $hello'
hello=hi: command not found

Чому я не можу встановити змінну середовища за допомогою змінної? Чи є префіксальна частина особливою частиною? Мені вдалося змусити його працювати, використовуючи eval спереду, але я досі не розумію, чому. Я використовую bash 4.4.


1
Ви можете використовувати envзамість того eval, який IIRC є більш безпечним, але повільніше.
wjandrea

Відповіді:


14

Я підозрюю, що це частина послідовності, яка вас зачепила:

Слова, які не є змінними призначеннями або перенаправленнями, розширюються (див. Розширення оболонки). Якщо якісь слова залишаються після розширення, першим словом вважається назва команди, а решта слова - аргументами

Це з довідкового посібника Bash у розділі Просте розширення команд.

У cmd=bashприкладі не встановлюються змінні середовища, і bash обробляє командний рядок через розширення параметра, залишаючи bash -c "echo hi".

У prefix=hello=hiприкладі знову немає змінних призначень у першому проході, тому обробка продовжує розширення параметрів, в результаті чого з'являється перше слово hello=hi.

Після обробки змінних призначень вони не повторно обробляються під час виконання команди.

Дивіться обробку та її результати у розділі set -x:

$ prefix=hello=hi
+ prefix=hello=hi
$ $prefix bash -c 'echo $hello'
+ hello=hi bash -c 'echo $hello'
-bash: hello=hi: command not found
$ hello=42 bash -c 'echo $hello'
+ hello=42
+ bash -c 'echo $hello'
42

Для більш безпечного варіанту "змінне розширення" -as- "змінні середовища", ніж eval, врахуйте пропозицію wjandrea щодоenv :

prefix=hello=hi
env "$prefix" bash -c 'echo "$hello"'
hi

Це не суворо присвоєння змінної командного рядка, оскільки ми використовуємо envголовну функцію утиліти для призначення команд змінних середовища, але вона досягає тієї ж мети. $prefixЗмінний розширюються під час обробки командного рядка, забезпечуючи ім'я = значення env, який передає його разом з bash.


3
Так само $foo=bar bash -c ...не буде працювати, оскільки $foo=barце не присвоєння змінної (як би це не було значення $foo), оскільки $foo=barне відповідає name=valueшаблону для присвоєння змінної.
муру

3

Тому що $prefixце не завдання. @Jeff має довше пояснення .

Ви можете зробити аналогічну функцію замість функції:

$ prefix() { hello=hi "$@"; }
$ prefix bash -c 'echo "$hello"'
hi

... і навіть ви можете їх укладати, якщо вам подобається:

$ foo() { foo=123 "$@"; }
$ bar() { bar=456 "$@"; }
$ foo bar bash -c 'echo "$bar $foo"'
456 123
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.