ไวยากรณ์หลายบรรทัดสำหรับการวางท่อ heredoc; พกพาได้ไหม


132

ฉันคุ้นเคยกับไวยากรณ์นี้:

cmd1 << EOF | cmd2
text
EOF

แต่เพิ่งค้นพบว่า bash ช่วยให้ฉันเขียน:

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 สเปรดชีตได้ คุณไม่ต้องสร้างไฟล์ชั่วคราว
Sridhar Sarnobat

อันแรกไม่ได้ผลสำหรับฉันใน z-shell ฉันไม่ชอบอันที่ 2 เพราะมันแปลกแยก | จากคำสั่งการสูญเสียสำนวน (?) ของท่อส่งเชลล์
Sridhar Sarnobat

คำตอบ:


104

ใช่มาตรฐาน POSIX อนุญาตสิ่งนี้ ตามเวอร์ชัน 2008:

เอกสารที่นี่จะถือเป็นคำเดียวที่ขึ้นต้นหลังจากคำถัดไป<newline>และต่อไปจนกว่าจะมีบรรทัดที่มีเฉพาะตัวคั่นและ a <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 นอกจากนี้คุณยังสามารถมีเอกสารที่นี่มากกว่าหนึ่งรายการสำหรับคำสั่งเดียวกัน (ตัวอย่างอื่น ๆ ใช้catการเรียกใช้สองครั้ง แต่ก็ใช้ได้เช่นกัน):

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

สิ่งนี้ถูกสร้างขึ้น (ใช้ 2 here-docs สำหรับ stdin) แต่ถ้าคุณคิดว่าจะให้อินพุตสำหรับตัวอธิบายไฟล์ที่แตกต่างกันมันก็สมเหตุสมผลทันที

นอกจากนี้ยังมีความเป็นไปได้ที่จะลดลงcatอย่างสิ้นเชิง ทำไมไม่จัดเตรียมเอกสารที่นี่โดยตรงให้กับcmd:

cmd << EOF
input
here
EOF

`` cat << EOF1 << EOF2 ก่อนที่นี่-doc EOF1 วินาทีที่นี่-doc EOF2 `` ข้างต้นใช้ไม่ได้
user1424739

@ user1424739 มันทำงานใน zsh และ bash ปัจจุบัน Ash และ ksh93 ดูเหมือนจะส่งออกเอกสารที่สองเท่านั้น
Jens

ทำไมต้องโหวตลง? หากมีบางอย่างไม่ถูกต้องโปรดให้โอกาสฉันแก้ไข
Jens

sudo tee /etc/securefile.conf <<EOFนี่คือสวยหวานเมื่อใช้
dragon788

มันใช้งานได้กับ bash เวอร์ชันใด การใช้ bash 4.4.19 (บน ubuntu 18.04.02) และ bash 5.0 (docker image) ฉันได้รับไฟล์ที่สองที่นี่ - doc เท่านั้น หรืออาจมีตัวเลือกเฉพาะ?
huelbois

17

อืมฉันคิดว่าใช่ตามการทดสอบใน bash ในโหมด POSIX:

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

เพียงแค่หนึ่งทราบเล็ก ๆ อื่น ๆ : ไม่ต้องใส่ช่องว่างใด ๆ EOFหลังจากที่ปิด ข้อความแจ้งจะทำงานแปลก ๆ และคุณจะสงสัยว่าเกิดอะไรขึ้น
Sridhar Sarnobat

2
การรัน bash ในโหมด POSIX จะปิดส่วนขยายบางส่วน แต่ไม่ได้ใช้วิธีใด ๆ เลยแม้แต่เกือบทั้งหมด ด้วยเหตุนี้แม้ว่าคำตอบนี้จะถูกต้องในแง่ของสิ่งที่ POSIX อนุญาต แต่เหตุผลก็ไม่สนับสนุนสิ่งนั้นอย่างมีประสิทธิภาพ
Charles Duffy

3

สวัสดีตรวจสอบสิ่งนี้เช่น

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

ความนับถือ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.