Многострочный синтаксис для трубопровода heredoc; это портативный?

Я знаком с этим синтаксисом:

cmd1 << EOF | cmd2
text
EOF

но только что обнаружил, что bash позволяет мне написать:

cmd1 << EOF |
text
EOF
cmd2

(heredoc используется как вход для cmd2). Это похоже на очень странный синтаксис. Он переносится?

Ответ 1

Да, стандарт POSIX позволяет это. Согласно версии 2008:

Настоящий документ должен рассматриваться как одно слово, которое начинается после следующий <newline> и продолжается до тех пор, пока не будет строка, содержащая только разделитель и <newline>, без знаков <blank> между ними. Затем начинается следующий документ, если он есть.

И включает в себя этот пример нескольких "здесь-документов" в одной строке:

cat <<eof1; cat <<eof2
Hi,
eof1
Helene.
eof2

Таким образом, нет проблем с перенаправлением или трубами. Ваш пример похож на что-то вроде этого:

cat file |
cmd

И грамматика оболочки (далее на связанной странице) содержит следующие определения:

pipe_sequence    :                             command
                 | pipe_sequence '|' linebreak command

newline_list     :              NEWLINE
                 | newline_list NEWLINE
                 ;
linebreak        : newline_list
                 | /* empty */

Таким образом, символу трубы может следовать конец строки и по-прежнему считать частью конвейера.

Ответ 2

Да, это в грамматике оболочки POSIX. Вы также можете иметь более одного здесь-документа для одной и той же команды (в некоторых других примерах используются две cat invocations, но это также работает):

cat <<EOF1 <<EOF2
first here-doc
EOF1
second here-doc
EOF2

Это надуманное (с использованием 2 здесь-docs для stdin), но если вы думаете о предоставлении ввода для разных дескрипторов файлов, это сразу имеет смысл.

Также существует возможность полностью отказаться от cat. Почему бы не сделать доступный здесь-документ доступным для cmd:

cmd << EOF
input
here
EOF

Ответ 3

Хмм, я полагаю, да, согласно тесту в bash в режиме POSIX:

$ bash --posix
$ cat <<EOF |
> ahoj
> nazdar
> EOF
> sed 's/a/b/'
bhoj
nbzdar