ทำไมฉันไม่สามารถอ่าน / dev / stdout ด้วยโปรแกรมแก้ไขข้อความได้?


9

ฉันเพิ่งเริ่มเรียนรู้ว่าทุกอย่างเป็นไฟล์TMบน Linux ซึ่งทำให้ฉันสงสัยว่าจะเกิดอะไรขึ้นถ้าฉันอ่านจาก / dev / stdout:

$ cat /dev/stdout 
^C
$ tail /dev/stdout 
^C

(นี่^Cคือฉันกำลังฆ่าโปรแกรมหลังจากแฮงค์)

เมื่อฉันลองvimฉันได้รับข้อความที่คิดไม่ถึง: "/ dev / stdout" ไม่ใช่ไฟล์ อ้าปากค้าง!

แล้วทำไมฉันถึงได้รับ Hangups หรือข้อความแสดงข้อผิดพลาดเมื่อฉันพยายามอ่าน "ไฟล์" เหล่านี้?


1
สิ่งที่กลุ่มพิจารณาไฟล์และสิ่งที่มีความหมายโดย "ทุกอย่างเป็นไฟล์" (ไม่มีเครื่องหมายการค้าที่เกี่ยวข้อง) ใน * ระวังไม่เหมือนกัน ดูเช่น# 1และ# 2
goldilocks

คำตอบ:


11

ทำไมฉันถึงได้รับ Hangups

คุณไม่ได้รับ "Hangups" จากcat(1)และtail(1)พวกเขากำลังปิดกั้นการอ่าน cat(1)รออินพุตและพิมพ์ออกมาทันทีที่เห็นบรรทัดสมบูรณ์:

$ cat /dev/stdout
foo
foo
bar
bar

นี่ฉันพิมพ์-fooEnterbarEnterCTRLD

tail(1)รออินพุตและพิมพ์เฉพาะเมื่อตรวจพบได้EOF:

$ tail /dev/stdout
foo
bar
foo
bar

นี่ฉันพิมพ์อีกครั้ง-fooEnterbarEnterCTRLD

หรือข้อความผิดพลาด

เป็นกลุ่มเดียวที่ให้ข้อผิดพลาด มันทำอย่างนั้นเพราะมันวิ่ง stat(2)เข้าหา/dev/stdoutกันและพบว่ามันไม่มีS_IFREGบิตตั้ง

/dev/stdoutเป็นไฟล์ แต่ไม่ใช่ไฟล์ปกติ อันที่จริงมีการเต้นในเคอร์เนลเพื่อให้รายการในระบบไฟล์ บน Linux:

$ ls -l /dev/stdout
lrwxrwxrwx 1 root root 15 May  8 19:42 /dev/stdout -> /proc/self/fd/1

ใน OpenBSD:

$ ls -l /dev/stdout
crw-rw-rw-  1 root  wheel   22,   1 May  7 09:05:03 2015 /dev/stdout

ใน FreeBSD:

$ ls -l /dev/stdout
lrwxr-xr-x  1 root  wheel  4 May  8 21:35 /dev/stdout -> fd/1

$ ls -l /dev/fd/1
crw-rw-rw-  1 root  wheel  0x18 May  8 21:35 /dev/fd/1

5

(เกือบ) ทุกอย่างเป็นไฟล์ แต่ไม่ใช่ทุกอย่างเป็นไฟล์ปกติ ไม่เหมาะสมที่จะเรียกเครื่องมือแก้ไขข้อความในสิ่งที่เป็นไฟล์พิเศษเช่นไดเรกทอรีซ็อกเก็ตเครือข่ายพอร์ตอนุกรม ฯลฯ

ไฟล์/dev/stdoutสามารถเป็นหนึ่งในหลาย ๆ สิ่งขึ้นอยู่กับตัวแปร unix:

  • ไฟล์“ พิเศษ” ซึ่งโดยปกติจะเป็นอุปกรณ์ตัวละคร
  • ลิงก์สัญลักษณ์“ วิเศษ” ที่ชี้ไปยังไฟล์ที่กระบวนการเข้าถึงมันเปิดไว้บนตัวให้คำอธิบายนี้
  • ลิงก์สัญลักษณ์ไปยังข้อใดข้อหนึ่งข้างต้น

ในกรณีใด ๆ การเปิด/dev/stdoutและไฟล์ที่คล้ายกันจะสร้างตัวอธิบายไฟล์ใหม่ที่เชื่อมโยงกับไฟล์เดียวกับที่แอปพลิเคชันได้เปิดไว้บนตัวอธิบายไฟล์ 1 แล้ว“ เอาต์พุตมาตรฐาน” หมายถึงตัวอธิบายไฟล์ 1 และเป็นเพียงระเบียบปฏิบัติ สำหรับผลลัพธ์ - เคอร์เนลไม่สนใจ

เมื่อคุณรันโปรแกรมในเทอร์มินัลตัวอธิบายมาตรฐานทั้งสาม (0 = อินพุตมาตรฐาน, 1 = เอาต์พุตมาตรฐาน, 2 = ข้อผิดพลาดมาตรฐาน) จะเปิดขึ้นบนอุปกรณ์เทอร์มินัล การอ่านจากอุปกรณ์นั้นจะส่งคืนอักขระที่ผู้ใช้พิมพ์และการเขียนไปยังอุปกรณ์นั้นจะแสดงข้อความในหน้าต่างเทอร์มินัล (ไม่มีวิธีมาตรฐานให้อุปกรณ์เทอร์มินัลอ่านเอาต์พุตที่แสดงหรือเพื่ออัดอินพุตเข้าไป)

เมื่อคุณเรียกใช้cat /dev/stdoutสิ่งนี้จะเหมือนกับcat /dev/stdinหรือcat /dev/stderrเพราะไฟล์ทั้งสามตัวนี้เชื่อมต่อกับไฟล์เดียวกัน: มันบอกcatให้อ่านจากเทอร์มินัล นั่นคือสิ่งที่catไม่มีข้อโต้แย้งทำเช่นกัน

ถ้าคุณวิ่งcat /dev/stdout >fooแล้ว/dev/stdoutจะอ้างถึงไฟล์foo- cat foo >fooคำสั่งที่เทียบเท่ากับ ทั้งนี้ขึ้นอยู่กับcatการดำเนินการอย่างใดอย่างหนึ่งอาจจะเกิดข้อผิดพลาดออก (รุ่น GNU บ่นว่า“แฟ้มใส่เป็นไฟล์ที่ส่งออก”) หรือมันอาจจะทำอะไรไม่ได้เพราะอ่านจากไฟล์fooที่ว่างเปล่า ( >fooเพียงแค่ตัดทอนมัน) ด้วยเวอร์ชันcatที่ไม่ตรวจจับกรณีพิเศษนี้หากfooไม่ว่างเปล่าcat /dev/stdout >>fooหรือสิ่งที่เทียบเท่าcat foo >>fooจะผนวกเนื้อหาของไฟล์เข้าด้วยกันอย่างไม่มีกำหนด

เมื่อคุณรันvim /dev/stdoutมันจะบ่นเพราะไม่รู้วิธีแก้ไขเทอร์มินัล (ซึ่งไม่สมเหตุสมผล)


2

catและtailกำลังค้นหาเนื้อหาทางเลือกตามด้วยจุดสิ้นสุดไฟล์ /dev/stdoutยังคงเปิดอยู่catและtailมองไปเรื่อย ๆ

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