การเปลี่ยนเส้นทางกับ `>>` เทียบเท่ากับ `>` หรือไม่เมื่อไฟล์เป้าหมายยังไม่มีอยู่?


80

พิจารณาเปลือกอย่าง Bash หรือ sh ความแตกต่างพื้นฐานระหว่าง>และ>>แสดงในกรณีเมื่อไฟล์เป้าหมายมีอยู่:

  • > ตัดไฟล์ให้มีขนาดเป็นศูนย์จากนั้นจึงเขียน;
  • >> ไม่ตัดทอนมันเขียน (ต่อท้าย) ที่ส่วนท้ายของไฟล์

หากไฟล์ไม่มีอยู่ไฟล์จะถูกสร้างด้วยขนาดศูนย์ แล้วเขียนถึง นี่เป็นเรื่องจริงสำหรับผู้ประกอบการทั้งสอง ดูเหมือนว่าโอเปอเรเตอร์จะเท่ากันเมื่อไฟล์เป้าหมายยังไม่มีอยู่

พวกเขาจริงเหรอ?

คำตอบ:


107

TL; DR

ไม่ใช่>>"โดยทั่วไปจะหาจุดสิ้นสุดของไฟล์" ในขณะที่>รักษาตัวชี้ไปยังตำแหน่งที่เขียนล่าสุด


คำตอบแบบเต็ม

(หมายเหตุ: การทดสอบทั้งหมดของฉันทำบน Debian GNU / Linux 9)

ความแตกต่างอื่น

ไม่พวกเขาไม่เทียบเท่า มีความแตกต่างอื่น มันอาจปรากฏตัวเองโดยไม่คำนึงว่าไฟล์เป้าหมายมีอยู่ก่อนหรือไม่

หากต้องการสังเกตให้เรียกใช้กระบวนการที่สร้างข้อมูลและเปลี่ยนเส้นทางไปยังไฟล์ที่มี>หรือ>>(เช่นpv -L 10k /dev/urandom > blob) ปล่อยให้มันรันและเปลี่ยนขนาดของไฟล์ (เช่นด้วยtruncate) คุณจะเห็นว่า>ยังคง (เพิ่มขึ้นเรื่อย ๆ ) ในขณะที่>>ต่อท้ายเสมอ

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

อีกตัวอย่างหนึ่งคือการผนวก (แยกต่างหาก>>) สิ่งพิเศษเมื่อกระบวนการสร้างข้อมูลกำลังทำงานและเขียนลงในไฟล์ สิ่งนี้คล้ายกับการขยายไฟล์

  • กระบวนการสร้างด้วย>จะเขียนที่ออฟเซ็ตที่ต้องการและเขียนทับข้อมูลพิเศษในที่สุด
  • กระบวนการสร้างด้วย>>จะข้ามข้อมูลใหม่และผนวกเข้ากับข้อมูลนั้น (สภาพการแข่งขันอาจเกิดขึ้นสตรีมทั้งสองอาจได้รับการอินเตอร์ลียังคงไม่ควรเขียนทับข้อมูล)

ตัวอย่าง

ในทางปฏิบัติมันมีความสำคัญอย่างไร? มีคำถามนี้ :

ฉันใช้กระบวนการที่สร้างเอาต์พุตจำนวนมากใน stdout กำลังส่งไปยังไฟล์ทั้งหมด [... ] ฉันสามารถใช้โปรแกรมการหมุนเวียนแบบบันทึกได้ไหม

คำตอบนี้บอกว่าการแก้ปัญหาอยู่logrotateกับcopytruncateตัวเลือกซึ่งทำหน้าที่ดังนี้

ตัดทอนไฟล์บันทึกดั้งเดิมหลังจากสร้างสำเนาแทนการย้ายไฟล์บันทึกเก่าและเลือกสร้างไฟล์ใหม่

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

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

ในกรณีนี้การใช้>>แทนที่จะ>ดีกว่าอย่างมีนัยสำคัญแม้ว่าไฟล์เป้าหมายกำลังจะถูกสร้างขึ้น


ประสิทธิภาพ

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


9
ดังนั้น>>โดยพื้นฐานแล้ว "พยายามค้นหาจุดสิ้นสุดไฟล์เสมอ" ในขณะที่>รักษาตัวชี้ไปยังตำแหน่งที่เขียนล่าสุด ดูเหมือนว่าอาจมีความแตกต่างของประสิทธิภาพเล็กน้อยในวิธีที่พวกเขาทำงานเช่นกัน ...
Mokubai

10
ในระดับสายระบบที่>>ใช้ธงO_APPEND open()และจริงๆแล้ว>ใช้O_TRUNCในขณะที่>>ไม่ การรวมกันของO_TRUNC | O_APPENDก็จะเป็นไปได้ภาษาเปลือกเพียงไม่ได้มีคุณสมบัติที่
ilkkachu

3
@jjmontes, แหล่งมาตรฐานจะเป็น POSIX: pubs.opengroup.org/onlinepubs/9699919799.2018edition/utilities/ …แต่แน่นอนว่าคู่มือของ Bash นั้นมีคำอธิบายเกี่ยวกับตัวดำเนินการเปลี่ยนเส้นทางซึ่งรวมถึงตัวที่ไม่ได้มาตรฐานที่สนับสนุน: gnu.org/ ซอฟต์แวร์ / bash / manual / html_node / Redirections.html
ilkkachu

2
@ilkkachu ฉันคิดว่านี่น่าสนใจเพราะมันอธิบายรายละเอียดเกี่ยวกับ O_APPEND ซึ่งฉันสงสัยหลังจากที่คุณแสดงความคิดเห็น :): stackoverflow.com/questions/1154446/…
jjmontes

1
@Mokubai ระบบปฏิบัติการใด ๆ ที่มีความยาวของไฟล์อยู่ในมือเมื่อมันเปิดอยู่และตรวจสอบการตั้งค่าสถานะและย้ายออฟเซ็ตไปยังจุดสิ้นสุดควรจะหายไปในการทำบัญชีอื่น ๆ ทั้งหมด พยายามที่จะเลียนแบบO_APPENDที่มีlseek()ก่อนwrite()จะแตกต่างกัน แต่มีต้องการจะเพิ่มค่าใช้จ่ายในการเรียกระบบ (และแน่นอนว่ามันจะไม่ทำงานเนื่องจากกระบวนการอื่นสามารถทำได้write()ระหว่าง)
ilkkachu
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.