วิธีทำความเข้าใจท่อ


21

เมื่อฉันใช้ไปป์ในการทุบตีฉันไม่ได้คิดถึงเรื่องนี้มากขึ้น แต่เมื่อฉันอ่านตัวอย่างรหัส C โดยใช้ system call pipe () ร่วมกับ fork () ฉันสงสัยว่าจะเข้าใจไพพ์ได้อย่างไรรวมถึงไพพ์นิรนามและไพพ์ที่มีชื่อ

มักจะได้ยินว่า "ทุกอย่างใน Linux / Unix เป็นไฟล์" ฉันสงสัยว่าไพพ์เป็นไฟล์จริงหรือไม่เพื่อให้ส่วนหนึ่งเชื่อมต่อการเขียนไปยังไฟล์ไพพ์และอีกส่วนหนึ่งอ่านจากไฟล์ไพพ์หรือไม่ ถ้าใช่ไฟล์ไพพ์ของไพพ์นิรนามจะถูกสร้างขึ้นที่ไหน? ใน / tmp, / dev หรือ ... ?

อย่างไรก็ตามจากตัวอย่างของ pipes ที่มีชื่อฉันยังได้เรียนรู้ว่าการใช้ไพพ์มีข้อได้เปรียบด้านพื้นที่และเวลามากกว่าการใช้ไฟล์ชั่วคราวอย่างชัดเจนอาจเป็นเพราะไม่มีไฟล์ที่เกี่ยวข้องในการใช้ไพพ์ ท่อดูเหมือนจะไม่เก็บข้อมูลเช่นเดียวกับไฟล์ ดังนั้นฉันจึงสงสัยว่าไพพ์เป็นไฟล์จริงๆ

คำตอบ:


23

เกี่ยวกับคำถามด้านประสิทธิภาพของคุณไพพ์มีประสิทธิภาพมากกว่าไฟล์เนื่องจากไม่จำเป็นต้องใช้ดิสก์ IO ดังนั้นจึงcmd1 | cmd2มีประสิทธิภาพมากกว่าcmd1 > tmpfile; cmd2 < tmpfile(ซึ่งอาจไม่เป็นจริงหากtmpfileสำรองข้อมูลบนดิสก์ RAM หรืออุปกรณ์หน่วยความจำอื่น ๆ ตามชื่อไปป์ แต่ถ้าเป็นไพพ์ที่มีชื่อcmd1ควรรันในพื้นหลังเนื่องจากเอาต์พุตสามารถบล็อกได้หากไพพ์เต็ม ) หากคุณต้องการผลมาจากcmd1และยังคงต้องส่งผลผลิตของตนไปcmd2คุณควรcmd1 | tee tmpfile | cmd2ที่จะช่วยให้cmd1และจะทำงานในแบบคู่ขนานหลีกเลี่ยงการอ่านดิสก์การดำเนินงานจากcmd2cmd2

ไปป์ที่มีชื่อจะมีประโยชน์ถ้ากระบวนการต่าง ๆ อ่าน / เขียนไปยังไปป์เดียวกัน พวกเขายังสามารถเป็นประโยชน์เมื่อโปรแกรมไม่ได้ออกแบบมาเพื่อการใช้งาน stdin / stdout สำหรับ IO มันจำเป็นต้องใช้ไฟล์ ฉันวางไฟล์เป็นตัวเอียงเพราะไพพ์ที่มีชื่อไม่ใช่ไฟล์ในมุมมองหน่วยเก็บข้อมูลเพราะมันอยู่ในหน่วยความจำและมีขนาดบัฟเฟอร์คงที่แม้ว่าจะมีรายการระบบไฟล์ (เพื่อการอ้างอิง) อื่น ๆสิ่งใน UNIX มีรายการระบบแฟ้มโดยไม่ต้องเป็นไฟล์: เพียงแค่คิดว่า/dev/nullหรือรายการอื่น ๆ ในหรือ/dev/proc

เนื่องจากไพพ์ (ชื่อและไม่มีชื่อ) มีขนาดบัฟเฟอร์คงที่การดำเนินการอ่าน / เขียนสามารถบล็อกได้ทำให้กระบวนการอ่าน / เขียนดำเนินไปในสถานะ IOWait นอกจากนี้คุณจะได้รับ EOF เมื่ออ่านจากบัฟเฟอร์หน่วยความจำเมื่อใด กฎเกี่ยวกับพฤติกรรมนี้มีการกำหนดไว้อย่างดีและสามารถพบได้ในมนุษย์

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

เกี่ยวกับ"everything in Linux/Unix is a file"ฉันไม่เห็นด้วย ไปป์ที่มีชื่อมีรายการระบบแฟ้ม แต่ไม่ใช่ไฟล์ที่แน่นอน ไพพ์ที่ไม่มีชื่อไม่มีรายการระบบไฟล์ (ยกเว้นอาจจะอยู่ใน/proc) อย่างไรก็ตามการดำเนินการ IO ส่วนใหญ่บน UNIX ทำได้โดยใช้ฟังก์ชั่นอ่าน / เขียนที่ต้องการfile descriptorรวมถึงไพพ์ที่ไม่มีชื่อ (และซ็อกเก็ต) ผมไม่คิดว่าเราสามารถพูดได้ว่าแต่เราก็สามารถพูดได้ว่า"everything in Linux/Unix is a file""most IO in Linux/Unix is done using a file descriptor"


ขอบคุณ! คำสั่งสองคำสั่งเชื่อมต่อกันโดยไพพ์ที่รันแบบขนานแทนที่จะเป็นคำสั่งที่สองเริ่มทำงานหลังจากคำสั่งแรกเสร็จสิ้นหรือไม่?
ทิม

ใช่คำสั่ง 2 นั้นทำงานแบบขนาน หากพวกเขาไม่ได้และการส่งออกที่ 1 มากกว่าบัฟเฟอร์มันจะถูกบล็อก คุณสามารถทดลองใช้งานได้โดยการทำงานcmd1 > fifoและcmd2 < fifoใน 2 เปลือกหอยที่แตกต่างกัน, mkfifo fifoการสร้างไปป์ที่มีชื่อด้วย
jfg956

การทดสอบอื่นที่คุณสามารถทำได้คือการฆ่าcmd2ในขณะที่cmd1ยังทำงานอยู่: cmd1อาจจะหยุดการรายงานไปป์ที่แตกหัก
jfg956

ขอบคุณ! คุณหมายถึงอะไรจะถูกบล็อก? หากเกิดเหตุการณ์นี้หมายความว่าวันที่ในสตรีมหลังบล็อกจะหายไปหรือไม่
ทิม

2
ข้อมูลไม่สูญหาย หากบัฟเฟอร์ของท่อเต็มcmd1เขียนไปยังท่อจะกลับเฉพาะเมื่อcmd2จะอ่านข้อมูลจากไปป์ ในทำนองเดียวกันการcmd2อ่านจากไปป์จะบล็อกหากบัฟเฟอร์ว่างเปล่าจนกว่าจะcmd1เขียนไปยังไปป์
jfg956

4

พื้นฐานสองประการของปรัชญา UNIX คือ

  1. เพื่อให้โปรแกรมขนาดเล็กที่ทำสิ่งหนึ่งที่ดี
  2. และคาดว่าเอาต์พุตของทุกโปรแกรมจะกลายเป็นอินพุตไปยังอีกโปรแกรมซึ่ง
    ยังไม่ทราบ

    การใช้ท่อช่วยให้คุณสามารถใช้เอฟเฟกต์ของ
    พื้นฐานการออกแบบทั้งสองนี้เพื่อสร้างกลุ่มคำสั่งที่ทรงพลังมากเพื่อให้ได้ผลลัพธ์ที่ต้องการ

    โปรแกรมบรรทัดคำสั่งส่วนใหญ่ที่ทำงานกับไฟล์ยังสามารถรับอินพุตตามมาตรฐานใน (อินพุตผ่านแป้นพิมพ์) และเอาต์พุตไปยังเอาต์พุตมาตรฐาน (พิมพ์บน
    หน้าจอ)

    คำสั่งบางคำสั่งถูกออกแบบมาเพื่อใช้งานภายในไพพ์เท่านั้นไม่สามารถทำงานกับไฟล์ได้โดยตรง

    ตัวอย่างtrคำสั่ง

  ls -C | tr 'a-z' 'A-Z'
    cmd1 | cmd2
  • ส่ง STDOUT ของ cmd1 ไปยัง STDIN ของ cmd2 แทนหน้าจอ

  • STDERR จะไม่ถูกส่งต่อข้ามท่อ

    ในระยะสั้นPipes is character (|)สามารถเชื่อมต่อคำสั่ง

    คำสั่งใด ๆ ที่เขียนไปยัง STDOUT สามารถใช้ทางด้านซ้ายมือของไพพ์

       ls - /etc | less 

    คำสั่งใด ๆ ที่อ่านจาก STDIN สามารถใช้ทางด้านขวาของไพพ์

       echo "test print" | lpr 

    ไปป์แบบดั้งเดิมคือ "ไม่มีชื่อ" เนื่องจากมีอยู่โดยไม่ระบุชื่อและยังคงมีอยู่ตราบเท่าที่กระบวนการกำลังทำงานอยู่ ไปป์ที่ระบุชื่อเป็นระบบถาวรและมีอยู่เกินอายุการใช้งานของกระบวนการและต้องถูกลบออกเมื่อไม่ได้ใช้งานอีกต่อไป กระบวนการโดยทั่วไปจะแนบไปกับไปป์ที่มีชื่อ (โดยปกติจะปรากฏเป็นไฟล์) เพื่อดำเนินการสื่อสารระหว่างกระบวนการ (IPC)

แหล่งที่มา: http://en.wikipedia.org/wiki/Named_pipe


3

เพื่อเสริมคำตอบอื่น ๆ ...

stdin และ stdout เป็นตัวอธิบายไฟล์และอ่านและเขียนราวกับว่าเป็นไฟล์ ดังนั้นคุณสามารถทำได้echo hi | grep hiและมันจะแทนที่ stdout ของ echo ด้วยไพพ์และแทนที่ stdin ของ grep ไปยังส่วนอื่น ๆ ของไพพ์นี้


1

ทุกอย่างเป็นไฟล์

หากเราใช้วลีนี้อย่างแท้จริงเราจะจบลงด้วยความหมายของ“ เรามีเพียงไฟล์และไม่มีอะไรอื่น” นี่ไม่ใช่การตีความที่ถูกต้องดังนั้นมันคืออะไร

เมื่อเราพูดว่า "ทุกอย่างเป็นไฟล์" เราจะไม่พูดว่าทุกอย่างถูกเก็บไว้ในดิสก์ เรากำลังบอกว่าทุกอย่างดูเหมือนไฟล์สามารถอ่านได้เขียนได้

ใน Unix เมื่อไฟล์หรือไฟล์ที่ไม่ได้เปิดแล้วมันจะถือว่าเป็นไฟล์ อย่างไรก็ตามไฟล์บางไฟล์อาจไม่รองรับการทำงานทั้งหมด เช่นไฟล์บางไฟล์ (ที่ไม่ใช่ไฟล์) ไม่รองรับการค้นหา: ไฟล์เหล่านั้นจะต้องอ่าน / เขียนตามลำดับ (นี่เป็นเรื่องจริงของไพพ์และซ็อกเก็ต)

ทุกอย่างมีชื่อไฟล์ (ในบางระบบ: เช่น Debian Gnu / Linux และ Gnu / Linux อื่น ๆ อีกมากมาย)

  • ไฟล์ที่เปิดทั้งหมดจะได้รับชื่อไฟล์ ดู/proc/self/fd/…
  • ซ็อกเก็ตเครือข่ายสามารถเปิดได้ด้วยชื่อไฟล์ดู/dev/tcp
    เช่นcat </dev/tcp/towel.blinkenlights.nl/23

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