В этом вопросе кто-то сообщает о проблеме, используя документ here со словом в кавычках в кавычках внутри $(...)
подстановки команд , где обратный слеш \
в конце строки внутри документа запускает продолжение строки, соединяющей строки , в то время как тот же документ здесь вне подстановки команд работает должным образом ,
Вот упрощенный пример документа:
cat <<'EOT'
abc ` def
ghi \
jkl
EOT
Это включает в себя одну обратную черту и одну обратную косую черту в конце строки. Разделитель указан, поэтому внутри тела не происходит никаких расширений. Во всех подобных Борне я могу найти, что это выводит содержание дословно. Если я помещу тот же документ в подстановку команд следующим образом:
x=$(cat <<'EOT'
abc ` def
ghi \
jkl
EOT
)
echo "$x"
тогда они больше не ведут себя одинаково
dash
,ash
,zsh
,ksh93
, BusyBoxash
,mksh
и SunOS 5,10 POSIXsh
все дает стенографическое содержание документа, как и раньше.- Bash 3.2 дает синтаксическую ошибку для непревзойденного обратного удара. С соответствующими обратными галочками он пытается запустить содержимое как команду.
- Bash 4.3 сворачивает "ghi" и "jkl" в одну строку, но не имеет ошибок.
--posix
Опция не влияет на это. Кусалананда говорит мне (спасибо!), Чтоpdksh
ведет себя так же .
В первоначальном вопросе я сказал, что это ошибка в парсере Bash. Это? [Обновление: да ] Соответствующий текст из POSIX (все из определения языка командной оболочки), который я могу найти:
- §2.6.3 Подстановка команд :
В форме $ (команда) все символы, следующие за открывающей скобкой и совпадающей с закрывающей скобкой, составляют команду. Любой допустимый сценарий оболочки может быть использован для команды , кроме сценария, состоящего исключительно из перенаправлений, который приводит к неопределенным результатам.
- §2.7.4 Here-Document :
Если какая - либо часть слова котируется, разделитель должен быть сформирован путем выполнения удаления цитаты на словах , а линия здесь-документ не должна быть расширена.
- §2.2.1 Escape-символ (обратная косая черта) :
Если <newline> следует за <backslash>, оболочка должна интерпретировать это как продолжение строки. <Backslash> и <newline> должны быть удалены перед разбиением ввода на токены.
- §2.3 Распознавание токенов :
Когда токен io_here был распознан грамматикой (см. « Грамматика оболочки» ), одна или несколько последующих строк, следующих непосредственно за следующим токеном NEWLINE, образуют тело одного или нескольких документов здесь и должны быть проанализированы в соответствии с правилами Here- Документ .
Когда он не обрабатывает io_here , оболочка должна разбить свой ввод на токены, применяя первое применимое правило ниже к следующему символу в своем вводе. ...
...
- Если текущим символом является <обратная косая черта>, одинарная кавычка или двойная кавычка, и он не заключен в кавычки, это влияет на цитирование последующих символов до конца цитируемого текста. Правила цитирования описаны в разделе «Цитирование» . Во время распознавания токена никакие замены фактически не должны выполняться, и результирующий токен должен содержать именно те символы, которые появляются во входных данных (кроме присоединения <newline>), без изменений, включая любые вложенные или заключающие в кавычки или операторы подстановки, между и концом цитируемого текста.
Моя интерпретация этого состоит в том, что все символы после $(
до окончания )
включают сценарий оболочки, дословно; появляется документ здесь, поэтому обработка обычного документа происходит вместо обычной токенизации; тогда здесь документ имеет разделитель в кавычках, что означает, что его содержимое обрабатывается дословно; и побег персонаж никогда не входит в это. Однако я вижу аргумент, что этот случай просто не рассматривается, и оба поведения допустимы. Возможно, я где-то пропустил и соответствующий текст.
- Эта ситуация прояснена в другом месте?
- На что должен опираться переносимый скрипт (теоретически)?
- Соответствует ли стандарт какой-либо из этих оболочек (Bash 3.2 / Bash 4.3 / всем остальным), предписанным стандартом? Запретный? Разрешенный?
источник
echo "$x"
, но любой способ проверки переменной работает. Я редактировал эту строку в нижней части.$(...)
тем, что есть на выходе ... Теперь, когда команда запускается в вашем примере в подоболочке (вbash
), она выдает ожидаемый результат. Только когда он превращается в подстановку команд, он сворачивает "ghi" и "jkl". Так что это ошибкаОтветы:
Это было задано в списке рассылки Bash, и сопровождающий подтвердил, что это ошибка
Они также упомянули, что текст в POSIX «не обязательно неоднозначный, но требует внимательного прочтения», поэтому я попросил разъяснений по этому поводу. Их ответ, включая описание проблемы и толкование стандарта, был следующим:
источник