คุณจะใช้การเปลี่ยนเส้นทางผลลัพธ์ร่วมกับ here-เอกสารและ cat ได้อย่างไร


56

สมมติว่าฉันมีสคริปต์ที่ฉันต้องการไพพ์ไปยังคำสั่งอื่นหรือเปลี่ยนเส้นทางไปยังไฟล์ (ไพพ์shสำหรับตัวอย่าง) สมมติว่าฉันใช้ทุบตี

ฉันสามารถทำได้โดยใช้echo:

echo "touch somefile
echo foo > somefile" | sh

ฉันสามารถทำสิ่งเดียวกันได้โดยใช้cat:

cat << EOF
touch somefile
echo foo > somefile
EOF

แต่ถ้าฉันแทนที่ "EOF" ด้วย "EOF | sh" แค่คิดว่ามันเป็นส่วนหนึ่งของ heredoc

ฉันจะสร้างมันขึ้นมาเพื่อให้catส่งออกข้อความจาก stdin แล้วไปป์ที่ตำแหน่งใด ๆ ?


touchจะมีอะไรที่คุณต้องการ? เป็นแค่อ่านไฟล์อินพุตและเปลี่ยนเส้นทางไปยังอีกด้วย stdout?
ราหุลปาติล

2
@RahulPatil แน่นอนมันไร้ประโยชน์ ฉันแค่ต้องการตัวอย่างที่มีมากกว่าหนึ่งบรรทัดเพื่อให้ภาพประกอบ heredoc ดีขึ้น และดูตัวอย่างโดยใช้echo- catฉันถูกสงสัยว่าเทียบเท่าของที่จะใช้
strugee

ตัวอย่างของคุณคือการสร้างสคริปต์ออกของสตริงหลายและผ่านโดยตรงไปยังsh shฉันพบว่าคิวของคุณกำลังมองหาการส่งออกข้อความของคำสั่งหลายคำรวมถึงเอกสาร HERE เพื่อส่งคำสั่งโดยตรง ซึ่งเป็นตัวอย่างที่ 2 ของคำตอบของ Ash
Dave X

คำตอบ:


91

มีหลายวิธีในการทำเช่นนี้ วิธีที่ง่ายที่สุดน่าจะเป็น:

cat <<EOF | sh
touch somefile
echo foo > somefile
EOF

อื่นซึ่งเป็นไวยากรณ์ที่ดีกว่าในความคิดของฉัน:

(
cat <<EOF
touch somefile
echo foo > somefile
EOF
) | sh

สิ่งนี้ทำงานได้ดี แต่ไม่มีเชลล์ย่อย:

{
cat <<EOF
touch somefile
echo foo > somefile
EOF
} | sh

รูปแบบเพิ่มเติม:

cat <<EOF |
touch somefile
echo foo > somefile
EOF
  sh

หรือ:

{ cat | sh; } << EOF
touch somefile
echo foo > somefile
EOF

อย่างไรก็ตามฉันคาดหวังว่าการใช้catคำถามของคุณจะเป็นตัวยึดตำแหน่งสำหรับสิ่งอื่น ถ้าไม่นำออกมาเช่นนี้

sh <<EOF
touch somefile
echo foo > somefile
EOF

ซึ่งอาจทำให้สิ่งนี้ง่ายขึ้น:

sh -c 'touch somefile; echo foo > somefile'

หรือ:

sh -c 'touch somefile
echo foo > somefile'

การเปลี่ยนเส้นทางเอาต์พุตแทนการไพพ์

sh >out <<EOF
touch somefile
echo foo > somefile
EOF

ใช้catเพื่อรับค่าเทียบเท่าecho test > out:

cat >out <<EOF
test
EOF

เอกสารที่นี่หลาย

( cat; echo ---; cat <&3 ) <<EOF 3<<EOF2
hi
EOF
there
EOF2

สิ่งนี้สร้างผลลัพธ์:

hi
---
there

นี่คือสิ่งที่เกิดขึ้น:

  • เชลล์จะเห็น( ... )และเรียกใช้คำสั่งที่ล้อมรอบในเชลล์ย่อย
  • แมวและเสียงสะท้อนนั้นเรียบง่ายพอ cat <&3กล่าวว่าการเรียกใช้แมวกับไฟล์อธิบาย (FD) 0 (stdin) เปลี่ยนเส้นทางจาก FD 3; กล่าวอีกนัยหนึ่งให้ป้อนค่าจาก fd 3
  • ก่อนที่(...)จะเริ่มเชลล์จะเห็นเอกสารทั้งสองที่นี่เปลี่ยนเส้นทางและทดแทน fd 0 ( <<EOF) และ fd 3 ( 3<<EOF2) ด้วย read-side ของไปป์
  • เมื่อคำสั่งเริ่มต้นเริ่มขึ้นเชลล์อ่าน stdin จนกว่า EOF จะมาถึงและส่งไปยังด้านการเขียนของไพพ์แรก
  • ถัดไปก็ทำเช่นเดียวกันกับ EOF2 และด้านเขียนของไพพ์ที่สอง

จากตัวอย่างที่สองถึงครั้งสุดท้ายคุณสามารถยกตัวอย่างด้วยการเปลี่ยนเส้นทาง stdout แทนการวางท่อได้หรือไม่?
strugee

ฉันแก้ไขคำตอบด้วยตัวอย่างการเปลี่ยนเส้นทาง นี่เป็นรูปแบบที่คุณต้องการแก้ไขหรือไม่ ถ้าไม่คุณสามารถให้บรรทัดแรกของส่วนนั้นชี้แจงได้ไหม
เถ้า

1
มันอาจช่วยให้เข้าใจว่าเชลล์ประมวลผลสิ่งนี้อย่างไร เมื่อทำการประเมินบรรทัดคำสั่งและค้นหา << EOF มันจะอ่านจากอินพุตมาตรฐานจนกว่าจะพบบรรทัดที่มี EOF เท่านั้นหรือสิ้นสุดการป้อนข้อมูล ทุกอย่างอื่นในบรรทัดคำสั่งดั้งเดิมที่ยังไม่ได้ประมวลผลแล้วดำเนินการต่อ ตัวอย่างเช่นเป็นไปได้ที่จะทำสิ่งนี้: (cat; echo ---; exec <&3; cat) <<EOF 3<<EOF2 >outจากนั้นให้อินพุตคำสั่งด้วยบล็อกที่นี่สองแถวในแถว
เถ้า

คำอธิบายของคุณเกี่ยวกับการประมวลผลเชลล์นั้นน่าสนใจ แต่เหนือหัวฉัน :) สิ่งที่ฉันอยากรู้คือสิ่งที่จะcatเทียบเท่าecho test > outได้กับการใช้ heredoc ในขณะที่ตัวอย่างที่คุณให้เพิ่มการเปลี่ยนเส้นทางในตอนท้ายของไพพ์
strugee

1
@OlivierDulac - ฉันเพิ่มตัวอย่าง heredoc หลายคำตอบ
เถ้า

1

ผมแค่อยากจะชี้ให้เห็นว่าการใช้เป็นเพียงเป็นที่ถูกต้องเป็นmeowEOF

สคริปต์นี้จะต่อท้ายMeow!ไฟล์ที่ชื่อcat:

#!/bin/sh
cat <<meow>> cat
Meow!
meow

บันทึกเป็นcatsและทำให้สามารถchmod +x catsเรียกทำงานได้ด้วยจากนั้นเรียกใช้ด้วย./cats:

$ ./cats
$ cat cat
Meow!
$ ./cats
$ cat cat
Meow!
Meow!

คำอธิบาย:

  • cat <<meowเป็นไวยากรณ์เอกสารที่นี่ meowมันสั่งสคริปต์เพื่อรับบล็อกข้อความที่เป็นไปตามบรรทัดนี้จนกว่าจะพบสตริง เนื้อหาจะถูกเอาท์พุท (หรือส่งไปตาม)
  • >> catcatท่อไฟล์ที่ชื่อว่า
  • การใช้>แทนที่จะ>>เป็นการเขียนทับไฟล์แทนที่จะเป็นการต่อท้าย
  • Meow!เป็นเนื้อหาของเอกสารที่นี่
  • meowเป็นเครื่องหมาย end สำหรับเอกสารที่นี่ เนื้อหาจะมีการใช้งาน>>, catต่อท้าย

ไปป์ทั้งไปยัง stdout และไปยังไฟล์:

ในการทำท่อที่คุณร้องขอไม่จำเป็นต้องใช้เอกสารที่นี่

catไม่สามารถส่งออกข้อความและส่งต่อข้อความได้ แต่teeเป็นคู่ที่สมบูรณ์แบบสำหรับสิ่งที่คุณขอ:

echo echo | tee tee

นี้ทั้งสองจะออกสตริงechoและเขียนไปยังแฟ้มชื่อechotee

คุณสามารถส่งผ่านผลลัพธ์ได้catหากเป็นส่วนหนึ่งของข้อกำหนดด้วย:

echo echo | tee tee | cat </dev/stdin

หรือเพียงแค่:

echo echo | tee tee | cat

เนื้อหาของไฟล์:

$ cat tee
echo

1
นี่ไม่ได้ตอบคำถามจริงๆ ยัง>ไม่ได้สร้างไปป์ตามที่แสดงหัวข้อย่อยล่าสุดของคุณ
strugee

2
@strugee >สามารถสร้างไปป์ได้zshเมื่อมีการเปลี่ยนเส้นทาง fd เดียวกันหลายครั้งเช่นเดียวกับในecho foo >&1 > teeหรือecho foo > tee | catโดยที่zshใช้ภายในteeเพื่อดึงข้อมูลเอาต์พุตของechoทั้งสองcatและteeไฟล์
Stéphane Chazelas

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