Что POSIX требует для цитируемых здесь документов внутри подстановки команд?


20

В этом вопросе кто-то сообщает о проблеме, используя документ here со словом в кавычках в кавычках внутри $(...)подстановки команд , где обратный слеш \в конце строки внутри документа запускает продолжение строки, соединяющей строки , в то время как тот же документ здесь вне подстановки команд работает должным образом ,

Вот упрощенный пример документа:

cat <<'EOT'
abc ` def
ghi \
jkl
EOT

Это включает в себя одну обратную черту и одну обратную косую черту в конце строки. Разделитель указан, поэтому внутри тела не происходит никаких расширений. Во всех подобных Борне я могу найти, что это выводит содержание дословно. Если я помещу тот же документ в подстановку команд следующим образом:

x=$(cat <<'EOT'
abc ` def
ghi \
jkl
EOT
)
echo "$x"

тогда они больше не ведут себя одинаково

  • dash, ash, zsh, ksh93, BusyBox ash, mkshи SunOS 5,10 POSIX shвсе дает стенографическое содержание документа, как и раньше.
  • 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 , оболочка должна разбить свой ввод на токены, применяя первое применимое правило ниже к следующему символу в своем вводе. ...

    ...

    1. Если текущим символом является <обратная косая черта>, одинарная кавычка или двойная кавычка, и он не заключен в кавычки, это влияет на цитирование последующих символов до конца цитируемого текста. Правила цитирования описаны в разделе «Цитирование» . Во время распознавания токена никакие замены фактически не должны выполняться, и результирующий токен должен содержать именно те символы, которые появляются во входных данных (кроме присоединения <newline>), без изменений, включая любые вложенные или заключающие в кавычки или операторы подстановки, между и концом цитируемого текста.

Моя интерпретация этого состоит в том, что все символы после $(до окончания )включают сценарий оболочки, дословно; появляется документ здесь, поэтому обработка обычного документа происходит вместо обычной токенизации; тогда здесь документ имеет разделитель в кавычках, что означает, что его содержимое обрабатывается дословно; и побег персонаж никогда не входит в это. Однако я вижу аргумент, что этот случай просто не рассматривается, и оба поведения допустимы. Возможно, я где-то пропустил и соответствующий текст.


  • Эта ситуация прояснена в другом месте?
  • На что должен опираться переносимый скрипт (теоретически)?
  • Соответствует ли стандарт какой-либо из этих оболочек (Bash 3.2 / Bash 4.3 / всем остальным), предписанным стандартом? Запретный? Разрешенный?

Можете ли вы показать нам, как вы производите свою продукцию во втором случае?
Джули Пеллетье

@JuliePelletier echo "$x", но любой способ проверки переменной работает. Я редактировал эту строку в нижней части.
Майкл Гомер

2
Похоже, это легко исправить. Похоже, этот патч работает по крайней мере: ignore_quoted_newline_in_quoted_hedoc.patch
geirha

1
Я думаю, что вы интерпретируете это правильно, и, мне кажется, стандарт довольно ясен, поскольку «оболочка должна расширить подстановку команд, выполнив команду в среде подоболочек [...] и заменив подстановку команд [...] стандартным выводом команда [...] " Таким образом, она запускает команду в подоболочке и заменяет ее $(...)тем, что есть на выходе ... Теперь, когда команда запускается в вашем примере в подоболочке (в bash), она выдает ожидаемый результат. Только когда он превращается в подстановку команд, он сворачивает "ghi" и "jkl". Так что это ошибка
IMO

2
@geirha Я сообщил об ошибке в Bash ; Я не собираюсь беспокоиться о pdksh, так как он, кажется, не имеет даже тени текущего обслуживания.
Майкл Гомер

Ответы:


5

Это было задано в списке рассылки Bash, и сопровождающий подтвердил, что это ошибка

Они также упомянули, что текст в POSIX «не обязательно неоднозначный, но требует внимательного прочтения», поэтому я попросил разъяснений по этому поводу. Их ответ, включая описание проблемы и толкование стандарта, был следующим:

Подстановка команды - красная сельдь; это актуально только в том смысле, что там указано, где была ошибка.

Разделитель документа here указан в кавычках, поэтому строки не расширяются. В этом случае оболочка читает строки из ввода, как если бы они были в кавычках. Если обратный слеш появляется в контексте, в котором он заключен в кавычки, он не действует как escape-символ (см. Ниже), и специальная обработка обратного слеша-новой строки не выполняется. Фактически, если какая-либо часть разделителя заключена в кавычки, строки документа здесь читаются как одиночные кавычки.

Текст в Posix 2.2.1 написан неловко, но означает, что обратный слеш обрабатывается только тогда, когда он не заключен в кавычки. Вы можете указать обратную косую черту и запретить все расширения только с помощью одинарных кавычек или другой обратной косой черты.

Читающая часть - это «не развернутый» текст, подразумевающий одинарные кавычки. В стандарте 2.2 говорится, что здесь документы - это «другая форма цитирования», но единственная форма цитирования, в которой слова вообще не раскрываются, - это одинарные кавычки. Таким образом, это форма цитирования, которая примерно так же, как одинарные кавычки, но не одинарные кавычки.


@ Скотт (1) Я считаю, что это отвечает на все вопросы, и нет ничего лишнего. Мой комментарий, который начинается с ответа, касается удаления, сделанного модератором, который неправильно понял ситуацию. (2) мне не хватает репутации. (3) Я бы оценил подобное поведение тех, кто удалял мои ответы, но я обязательно учту это в будущем. Спасибо за мысли.
Кевин

Я хотел сказать, что большая часть вашего первого абзаца - это разговор с Майклом Мрозеком, а не ответ на вопрос. Я понимаю, что у вас недостаточно репутации, чтобы комментировать какие-либо посты, но я считаю, что у вас достаточно для мета и чата.
Скотт

1
@ Скотт Я понимаю и ценю, что вы пытаетесь упростить ответ, но ранее я опубликовал этот точно оптимизированный ответ (только цитату и ссылку на него), и он был удален модератором (без обсуждения!), И я не вижу ссылок в удаленном сообщении, чтобы общаться и оспаривать это решение. Я надеялся, что, ответив на его необоснованную критику, он выживет после удаления, будет принят спрашивающим, а затем я изменю ответ, удалив преамбулу.
Кевин
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.