คุณได้รับคำตอบที่ดีมากแล้ว ฉันขอเน้นว่ามีสองแนวคิดที่แตกต่างกันที่นี่ความเข้าใจซึ่งช่วยอย่างมาก:
พื้นหลัง: ตัวอธิบายไฟล์เทียบกับตารางไฟล์
ไฟล์ descriptor ของคุณเป็นเพียงตัวเลข 0 ... n ซึ่งเป็นดัชนีในตาราง descriptor ไฟล์ในกระบวนการของคุณ ตามแบบแผน STDIN = 0, STDOUT = 1, STDERR = 2 (โปรดทราบว่าคำศัพท์STDIN
อื่น ๆ ที่นี่เป็นเพียงสัญลักษณ์ / มาโครที่ใช้โดยการประชุมในภาษาการเขียนโปรแกรมและหน้าคนไม่มีวัตถุ "จริง" เรียกว่า STDIN สำหรับ จุดประสงค์ของการสนทนานี้ STDIN คือ 0 เป็นต้น)
ตารางตัวอธิบายไฟล์นั้นในตัวมันเองไม่มีข้อมูลใด ๆ เกี่ยวกับไฟล์จริง แต่จะมีตัวชี้ไปยังตารางไฟล์อื่น หลังมีข้อมูลเกี่ยวกับไฟล์จริง (หรืออุปกรณ์บล็อกหรือไปป์หรืออะไรก็ตามที่ Linux สามารถจัดการผ่านกลไกไฟล์) และข้อมูลเพิ่มเติม (เช่นไม่ว่าจะเป็นการอ่านหรือเขียน)
ดังนั้นเมื่อคุณใช้>
หรือ<
ในเชลล์คุณเพียงแค่เปลี่ยนพอยน์เตอร์ของไฟล์ descriptor ตามลำดับเพื่อชี้ไปยังสิ่งอื่น ไวยากรณ์2>&1
เพียงแค่บ่งชี้ 2 ไปที่ใดก็ได้ 1 คะแนน > file.txt
เพียงแค่เปิดfile.txt
สำหรับการเขียนและให้ STDOUT (ไฟล์ decsriptor 1) ชี้ไปที่
มีสารพัดอื่น ๆ เช่น2>(xxx)
(เช่น: สร้างกระบวนการใหม่ทำงานxxx
สร้างไพพ์เชื่อมต่อไฟล์ descriptor 0 ของกระบวนการใหม่ไปยังจุดสิ้นสุดการอ่านของไพพ์และเชื่อมต่อไฟล์ descriptor 2 ของกระบวนการดั้งเดิมไปยังจุดสิ้นสุดการเขียนของ ท่อ).
นี่เป็นพื้นฐานสำหรับ "file handle magic" ในซอฟต์แวร์อื่นที่ไม่ใช่เชลล์ของคุณ ตัวอย่างเช่นในสคริปต์ Perl ของคุณให้dup
ไลเซนส์ตัวอธิบายไฟล์ STDOUT เป็นอีกตัวหนึ่ง (ชั่วคราว) จากนั้นเปิด STDOUT อีกครั้งเป็นไฟล์ชั่วคราวที่สร้างขึ้นใหม่ จากจุดนี้เป็นต้นไปเอาต์พุต STDOUT ทั้งหมดจากสคริปต์ Perl ของคุณเองและการsystem()
เรียกใช้สคริปต์ทั้งหมดจะสิ้นสุดในไฟล์ชั่วคราวนั้น เมื่อเสร็จแล้วคุณสามารถdup
STDOUT ของคุณไปที่ descriptor ชั่วคราวที่คุณบันทึกไว้และ presto ทั้งหมดนี้เป็นเหมือนเดิม คุณสามารถเขียนไปที่ descriptor ชั่วคราวนั้นได้ในขณะที่เอาท์พุท STDOUT ที่แท้จริงของคุณไปที่ไฟล์ชั่วคราวคุณยังสามารถเอาท์พุทของจริง ๆ ไปยังSTDOUT ตัวจริง
ตอบ
หากต้องการใช้ข้อมูลพื้นหลังที่ให้ไว้กับคำถามของคุณ:
เชลล์สั่งรันคำสั่งและเปลี่ยนเส้นทางสตรีมในลำดับใด
จากซ้ายไปขวา
<command> > file.txt 2>&1
fork
ออกกระบวนการใหม่
- เปิด
file.txt
และเก็บตัวชี้ไว้ในตัวอธิบายไฟล์ 1 (STDOUT)
- ชี้ STDERR (ตัวอธิบายไฟล์ 2) ไปยังสิ่งที่ fd 1 ชี้ไปในขณะนี้ (ซึ่งเป็น
file.txt
หลักสูตรที่เปิดอยู่แล้ว)
exec
<command>
เห็นได้ชัดว่านี่เปลี่ยนเส้นทาง stderr ไปยัง stdout ก่อนจากนั้น stdout ที่ได้จะถูกเปลี่ยนเส้นทางไปยัง file.txt
นี่จะสมเหตุสมผลถ้ามีเพียงหนึ่งตาราง แต่ตามที่อธิบายข้างต้นมีสอง ตัวให้คำอธิบายไฟล์ไม่ได้ชี้ไปซ้ำ ๆ กันมันไม่มีเหตุผลที่จะคิดว่า "เปลี่ยนเส้นทาง STDERR ไปยัง STDOUT" ความคิดที่ถูกต้องคือ "ชี้ STDERR ไปยังทุกจุดของ STDOUT" หากคุณเปลี่ยน STDOUT ในภายหลัง STDERR จะคงอยู่ในที่เดิมมันจะไม่ไปพร้อมกับการเปลี่ยนแปลงเพิ่มเติมใน STDOUT อย่างน่าอัศจรรย์