Почему кавычки в сценариях оболочки ведут себя иначе, чем кавычки в командах оболочки? - PullRequest
0 голосов
/ 13 января 2019

Я использую WSL (Ubuntu 18.04) в Windows 10 и bash.

У меня есть файл filename.gpg с содержанием:

export SOME_ENV_VAR='123'

Теперь я запускаю следующие команды:

$ $(gpg -d filename.gpg)
$ echo $SOME_ENV_VAR
'123' <-- with quotes

Однако, если я запускаю его непосредственно в оболочке:

$ export SOME_ENV_VAR='123'
$ echo $SOME_ENV_VAR
123 < -- without quotes

Почему он так себя ведет? Почему существует разница между выполнением команды, использующей $(), и ее непосредственным выполнением?

В сторону: у меня все работает, используя eval $(gpg -d filename), я понятия не имею, почему это работает.

1 Ответ

0 голосов
/ 14 января 2019

Кавычки в сценариях оболочки не ведут себя иначе, чем кавычки в командах оболочки.

С синтаксисом $(gpg -d filename.gpg) вы выполняете не сценарий оболочки, а обычную отдельную команду.

Что делает ваша команда

  1. Выполняется gpg -d filename.gpg
  2. Из результата в качестве команды для выполнения берется первое (отделенное IFS) слово
  3. Он принимает каждые другие (разделенные IFS) слова, включая слова из дополнительных строк, в качестве параметров
  4. Выполняет команду

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

  1. Удалите слово export из filename.gpg: тогда команда будет SOME_ENV_VAR='123', которая не понимается как присвоение переменной (вы получите SOME_ENV_VAR='123': command not found).
  2. Если вы добавите несколько строк, они будут восприниматься не как отдельные командные строки, а как параметры самой первой команды (export).
  3. Если вы измените export SOME_ENV_VAR='123' на export SOME_ENV_VAR=$PWD, SOME_ENV_VAR будет содержать не содержимое переменной PWD, а строку $var

Почему это так?

См. , как bash выполняет расширение при анализе команды.

Есть много шагов. $(...) называется «подстановка команд» и является четвертым этапом. Когда это будет сделано, ни один из предыдущих шагов не будет выполнен снова. Это объясняет, почему ваша команда не работает, когда вы удаляете слово export, и почему переменные не подставляются в результат.

Более того, «удаление цитаты» является последним шагом, а руководство гласит :

все вхождения без кавычек символов ‘\’, ‘'’ и ‘" ’ Не в результате одного из вышеперечисленных расширений удалены

Поскольку одинарные кавычки были результатом расширения «подстановка команд», они не были удалены Вот почему содержимое SOME_ENV_VAR составляет '123', а не 123.

Почему eval работает?

Потому что eval запускает еще один полный анализ своих параметров. Весь набор расширений запускается снова.

Из руководства :

Аргументы объединяются в одну команду, которая затем читается и выполняется

Обратите внимание, что это означает, что вы все еще запускаете одну отдельную команду, а не сценарий оболочки. Если ваш filename.gpg скрипт имеет несколько строк, последующие строки будут добавлены в список аргументов первой (и единственной) команды.

Что мне тогда делать?

Просто используйте source вместе с процессом замены .

source <(gpg -d filename.gpg)

В отличие от eval, source используется для выполнения сценария оболочки в текущем контексте. Подстановка процесса предоставляет псевдо-имя файла, которое содержит результат подстановки (то есть вывод gpg).

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