Не могу понять, почему bash переменные не могут быть назначены таким образом - PullRequest
1 голос
/ 01 мая 2020

Я застрял, пытаясь понять (читая GNU Bash Справочное руководство ), почему я не могу назначить переменную таким образом:

myvar=var
${myvar}=42

Я ожидаю, что после вторая строка, значение var равно 42, но все, что я получаю, это:

command not found: var=42

Я буду следовать руководству (конечно, с ошибками в моих комментариях в скобках ...), чтобы лучше объяснить, почему я я застрял:

  1. bash читает ввод из командной строки (в этом случае), и хорошо хорошо, пусть он читает.
  2. bash разбивает ввод на слова и операторы (нет цитирование здесь, поэтому я пропускаю правило цитаты ...). Эти токены разделены метасимволами (= $ {} не являются метасимволами, поэтому должен быть один токен: вся строка)
  3. bash разбивает токен на простые и сложные команды (здесь я ожидаю '= 'интерпретируется как присваивание, $ {myvar} - lvalue, а 42 - rvalue).
  4. bash выполняет различное расширение. (${myvar} следует заменить на var)
  5. bash выполняет все необходимые перенаправления (здесь перенаправление отсутствует).
  6. bash выполняет команду (поэтому здесь bash следует назначить 42 для var)

Ответы [ 2 ]

5 голосов
/ 01 мая 2020

Символ = не является метасимволом.

Давайте сначала начнем с первого упоминания о присвоении переменной: Раздел 3.4 Параметры оболочки :

A параметр - это объект, который хранит значения. Это может быть name, число [для позиционных параметров $0, $1, et c.] Или один из специальных символов, перечисленных ниже. переменная - это параметр, обозначаемый name. Переменная имеет атрибуты значение и ноль или более . [...]

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

Переменная может быть назначена оператором вида

name=[value]

Если значение не задано, переменной присваивается нулевая строка. Все значения в go расширение тильды, расширение параметров и переменных, подстановка команд, расширение арифметики c и удаление кавычек (подробно описано ниже).

(текст в мое дополнение - квадратная скобка).

И нет никаких упоминаний о том, что name проходит через какие-либо расширения.

Кстати, name определяется как :

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

Если мы продолжим чтение, мы получим Раздел 3.7.1 Простое расширение команд , где мы читаем:

Когда выполняется простая команда, оболочка выполняет следующие расширения, назначения и перенаправления слева направо.

  1. Слова, которые синтаксический анализатор пометил как назначения переменных (предшествующие имя команды) и перенаправления сохраняются для последующей обработки.
  2. Раскрыты слова, которые не являются назначениями переменных или перенаправлениями (см. Расширения оболочки ). Если после раскрытия остаются какие-либо слова, первое слово считается именем команды, а остальные слова являются аргументами.
  3. Перенаправления выполняются, как описано выше (см. Перенаправления ).
  4. Текст после '=' в каждом назначении переменной подвергается расширению тильды, расширению параметров, подстановке команд, арифметическому расширению и удалению кавычек перед присвоением переменной.

И снова, только значение подвергается расширению.


Теперь, используя спецификации POSIX, Раздел 2.10.2 Правила грамматики оболочки упоминает:

[Назначение имени предшествующей команды]

a. [Когда первое слово]

Если TOKEN не содержит символ '=', применяется правило 1. В противном случае применяется 7b.

b. [Не первое слово]

Если TOKEN содержит символ без кавычек (как определено при применении правила 4 из распознавания токенов), который не является частью раскрытия встроенного параметра, подстановки команды или конструкции расширения арифметики c (как определено при применении правила 5 из Распознавания токенов):

  • Если TOKEN начинается с '=', то должно применяться правило 1.

  • Если все символы в TOKEN, предшествующие первой такой форме, имеют действительное имя (см. Имя XBD ), должен быть возвращен токен ASSIGNMENT_WORD.

  • В противном случае не указано, применяется ли правило 1 или возвращается ASSIGNMENT_WORD.

c. В противном случае должно применяться правило 1.

Назначение имени в возвращенном токене ASSIGNMENT_WORD должно происходить, как указано в Простых командах.

где допустимое имя определяется как :

В языке команд оболочки - слово, состоящее только из подчеркиваний, цифр и алфавитов из переносимого набора символов. Первый символ имени не является ди git.

2 голосов
/ 01 мая 2020

Шаг 3 не распознает ${myvar}=42 как назначение, потому что часть перед = не является допустимым идентификатором; это еще не расширенное расширение параметров. В разделе «Определения» справочной страницы имя определяется как

Слово, состоящее только из букв c букв и знаков подчеркивания и начинающееся с алфавита c символ или занижение. Также называется идентификатором.

Обратите внимание, что ${myvar} не является именем, поскольку оно начинается с $.

Позже, в разделе «Параметры», присваивание определяется с помощью:

Переменная может быть назначена оператором вида

Таким образом, ${myvar}=42 является , а не назначением.

В результате слово остается без изменений до шага 4, когда расширение происходит, в результате чего var=42.

bash больше не ищет назначений, поэтому к моменту перехода к шагу 6 слово в позиции команды будет var=42, которое не может быть найдено как команда. Проще говоря, назначение - это , а не , своего рода команда.

В отличие от этого, declare "$myvar=42" работает, потому что назначение является побочным эффектом команды declare var=42, созданной на шаге 4, при выполнении в шаге 6.

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