Багаторядковий синтаксис для прокладки гередока; це портативний?


132

Мені знайомий цей синтаксис:

cmd1 << EOF | cmd2
text
EOF

але щойно виявив, що баш дозволяє мені писати:

cmd1 << EOF |
text
EOF
cmd2

(heredoc використовується як вхід до cmd1, а вихід cmd1 передається в cmd2). Це здається дуже незвичайним синтаксисом. Це портативно?


Я прийшов сюди , щоб знайти хороший спосіб розщеплення цього на кілька рядків: big-long-command1 with lots of args << EOF | big-long-command2 with lots of args. "Незвичайний синтаксис" здається найкращим способом.
PaulC

Одним із зручних випадків використання для цього є те, що ви намагаєтесь перетворити таблицю з обмеженим простором у таку, яка обмежена вкладками, щоб ви могли вставити її в електронні таблиці Google. Вам не доведеться створювати тимчасовий файл.
Шрідхар Сарнобат

Перший не працював для мене в z-shell. Мені не подобається другий, тому що він відчужує | з команди, втрачаючи ідіотичність (?) оболонки трубопроводів.
Шрідхар Сарнобат

Відповіді:


104

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

Отже, символ труби може супроводжуватися кінцевим рядком і все ще вважатися частиною трубопроводу.


26

Так, це в граматиці оболонки POSIX. Ви також можете мати більше одного тут-doc для тієї ж команди (деякі інші приклади використовують два catвиклики, але це також працює):

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

Це надумано (використовуючи 2 тут-документа для stdin), але якщо ви думаєте надати введення для різних дескрипторів файлів, це одразу має сенс.

Також є можливість скинути catцілком . Чому б не зробити цей документ прямо доступним для cmd:

cmd << EOF
input
here
EOF

`` `cat << EOF1 << EOF2 перший here-doc EOF1 другий тут-doc EOF2` `` Наведене вище не працює.
користувач1424739

@ user1424739 Це працює в поточному zsh і bash. Попіл і ksh93, здається, видають лише другий тут doc.
Єнс

Чому потік? Якщо є щось неточне, надайте мені можливість виправити.
Єнс

Це досить солодко при використанні sudo tee /etc/securefile.conf <<EOF.
dragon788

На якій версії bash вона працює? Використовуючи bash 4.4.19 (на ubuntu 18.04.02) та bash 5.0 (зображення докера), я отримав лише другий тут-doc. А може, є конкретний варіант?
huelbois

17

Хм, я вважаю, що так, згідно з тестом на баш в режимі POSIX:

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

Ще одна крихітна примітка: не залишайте пробілів після закриття EOF.
Підказки

2
Запуск bash в режимі POSIX відключає деякі розширення, але не будь-яким чином, навіть майже всі. Таким чином, хоча ця відповідь правильна з точки зору того, що дозволяє POSIX, її міркування не підтримують це дуже ефективно.
Чарльз Даффі

3

Привіт, перевіри це, наприклад

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

з повагою

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.