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

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

cmd1 << EOF | cmd2
text
EOF

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

cmd1 << EOF |
text
EOF
cmd2

(здесьдокумент используется в качестве входных данных для cmd1, а выходные данные cmd1 передаются в cmd2). Это кажется очень странным синтаксисом. Это портативно?


person William Pursell    schedule 12.08.2011    source источник
comment
Я пришел сюда, чтобы найти хороший способ разбить это на несколько строк: big-long-command1 with lots of args << EOF | big-long-command2 with lots of args. Странный синтаксис кажется лучшим способом.   -  person PaulC    schedule 31.12.2014
comment
Один из удобных случаев использования этого — когда вы пытаетесь преобразовать таблицу, разделенную пробелами, в таблицу, разделенную табуляцией, чтобы вы могли вставить ее в электронные таблицы Google. Вам не придется создавать временный файл.   -  person Sridhar Sarnobat    schedule 05.01.2018
comment
Первый не работал у меня в z-shell. Мне не нравится второй, потому что он отчуждает | из команды, теряя идиоматичность (?) конвейеров оболочки.   -  person Sridhar Sarnobat    schedule 05.01.2018


Ответы (4)


Да, стандарт 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 */

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

person Ned Deily    schedule 12.08.2011

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

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

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

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

cmd << EOF
input
here
EOF
person Jens    schedule 20.05.2012
comment
``` cat ‹‹EOF1 ‹‹EOF2 первый здесь-doc EOF1 второй здесь-doc EOF2 ``` Вышеупомянутое не работает. - person user1424739; 01.06.2015
comment
@user1424739 user1424739 Это работает в текущих zsh и bash. Ясень и кш93 вроде выводят здесь только второй док. - person Jens; 01.06.2015
comment
Почему минус? Если есть что-то неточное, пожалуйста, дайте мне возможность исправить. - person Jens; 02.01.2017
comment
Это довольно мило при использовании sudo tee /etc/securefile.conf <<EOF. - person dragon788; 20.07.2017
comment
На какой версии bash работает? Используя bash 4.4.19 (на ubuntu 18.04.02) и bash 5.0 (образ докера), я получил только второй здесь-док. Или может есть конкретный вариант? - person huelbois; 05.07.2019

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

$ bash --posix
$ cat <<EOF |
> ahoj
> nazdar
> EOF
> sed 's/a/b/'
bhoj
nbzdar
person Tomas    schedule 12.08.2011
comment
Еще одно маленькое замечание: не ставьте пробелов после закрывающего EOF. Подсказка будет вести себя странно, и вы будете задаваться вопросом, что, черт возьми, не так - person Sridhar Sarnobat; 05.01.2018
comment
Запуск bash в POSIX-режиме отключает некоторые расширения, но ни в коем случае, даже почти все. Таким образом, хотя этот ответ является правильным с точки зрения того, что позволяет POSIX, его аргументация не очень эффективно поддерживает это. - person Charles Duffy; 05.01.2018

Привет, проверьте это, например

#!/bin/sh
( base32 -d | base64 -d )<<ENDOFTEXT
KNDWW42DNNSHS5ZXPJCG4MSVM5MVQVT2JFCTK3DELBFDCY2IIJYGE2JUJNHWS22LINVHQMCMNVFD
CWJQIIZVUV2JOVNEOVJLINTW6PIK
ENDOFTEXT

с уважением

person buc    schedule 21.03.2019