ทุบตีเปิดไฟล์ใน O_APPEND เมื่อใช้“ >>” บน linux หรือไม่


38

ถ้าเราใช้echo 1234 >> some-fileแล้วเอกสารระบุว่าเอาท์พุทจะถูกผนวกเข้า

ฉันเดาว่าถ้าไม่มีไฟล์บางไฟล์ O_CREAT จะสร้างไฟล์ใหม่ ถ้า>ใช้แล้ว O_TRUNC จะตัดทอนไฟล์ที่มีอยู่

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

ฉันกำลังถามเรื่องนี้เพราะกระบวนการ conserver เขียนทับเครื่องหมายบางตัวที่ใส่โดย echo เมื่อไฟล์เอาต์พุตมาจากจุดเมานต์ของ NFS & เอกสารของ NFS บอกว่า O_APPEND ไม่รองรับเซิร์ฟเวอร์ดังนั้นเคอร์เนลไคลเอ็นต์จะต้องจัดการมัน ฉันเดาว่ากระบวนการ conserver ใช้ O_APPEND แต่ไม่แน่ใจในการทุบตี>>กับ linux ดังนั้นจึงถามคำถามที่นี่


12
ปัญหาเกี่ยวกับ NFS นั้นไม่O_APPENDได้รับการสนับสนุน ปัญหาคือมันถูกลอกเลียนแบบ บนระบบไฟล์โลคัลกระบวนการหลายกระบวนการที่เขียนไปยังไฟล์เดียวกันที่เปิดด้วยO_APPEND จะไม่เขียนทับข้อมูลของกันและกัน บน NFS O_APPENDถูกเลียนแบบโดยพยายามหาจุดจบก่อนการเขียนซึ่งทำให้ความเป็นไปได้ของสภาพการแข่งขัน ไม่มีวิธีแก้ไขปัญหานี้ใน NFS ตัวเขียนแบบขนานแต่ละตัวจำเป็นต้องเขียนไฟล์ของตัวเอง วิธีเดียวในการแก้ไขปัญหานี้คือการตั้งค่ากระบวนการเซิร์ฟเวอร์บนเซิร์ฟเวอร์ NFS มีการบันทึก loggers |nc server portและให้เซิร์ฟเวอร์ผนวกข้อมูลที่เข้ามาลงในบันทึก
Guntram Blohm สนับสนุน Monica

@GuntramBlohm, +1 ขอบคุณสำหรับการยืนยัน โดยทั่วไปข้อเสนอแนะของคุณคือการใช้กระบวนการเขียนเพียงไฟล์เดียวเท่านั้นและกระบวนการเขียนอื่น ๆ ทั้งหมดจะผ่านกระบวนการนี้
เปรม

คำตอบที่ดีมากมายไม่แน่ใจว่าคำตอบแบบใดที่ฉันควรยอมรับ Bruce Ediger ตัวแรกแสดงให้เห็นว่ามีการใช้ O_APPEND ถัดไปแบบสุ่ม 832 แสดงให้เห็นว่านี่เป็นมาตรฐาน ในที่สุด Eric Renouf แสดงซอร์สโค้ดด้วยคำตอบเดียวกัน มุมมองทั้งสามนี้เพิ่มเข้ากับภาพสุดท้ายที่สมบูรณ์
เปรม

6
ในระยะสั้น NFS เป็นภาระของข้อบกพร่องและไม่ควรใช้
. ..

2
ใช่ แต่เราได้เรียนรู้วิธีย้อนกลับไปเมื่อ O_EXCL ถูกคิดค้น
เควิน

คำตอบ:


60

ฉันวิ่งไปนี้strace -o spork.out bash -c "echo 1234 >> some-file"เพื่อหาคำถามของคุณ นี่คือสิ่งที่ฉันพบ:

open("some-file", O_WRONLY|O_CREAT|O_APPEND, 0666) = 3

ไม่มีไฟล์ชื่อ "some-file" อยู่ในไดเรกทอรีที่ฉันรันechoคำสั่ง


50

สิ่งนี้ไม่เพียง แต่ทำใน Bash แต่เป็นไปตามมาตรฐาน

จากสเปค Unix เดียว :

การเปลี่ยนเส้นทางเอาต์พุตที่ต่อท้ายจะทำให้ไฟล์ที่มีชื่อเป็นผลมาจากการขยายคำที่จะเปิดสำหรับเอาต์พุตบน descriptor ไฟล์ที่กำหนด ไฟล์ถูกเปิดราวกับว่าฟังก์ชั่นopen ()ตามที่กำหนดไว้ในไดรฟ์ข้อมูล System Interfaces ของ POSIX.1-2008 ถูกเรียกด้วยแฟล็ก O_APPEND หากไฟล์ไม่มีอยู่ไฟล์นั้นจะถูกสร้างขึ้น

เชลล์ที่สอดคล้องกับ POSIX ใด ๆ จึงต้องทำ ในบางระบบยูนิกซ์/bin/shอาจจะไม่ใช่ POSIX เปลือกบอร์น (The Bourne เปลือกถูกเขียนเดิมก่อนที่จะO_APPENDถูกคิดค้น) และสามารถใช้ได้ POSIX เปลือกมักจะจะkshซึ่งจะสามารถเป็นshในสถานที่เส้นทางที่แตกต่างกันเช่น /usr/xpg4/binSolaris


2
น่าสนใจหนึ่งเชลล์ที่ไม่ทำคือเชลล์ Bourne เชลล์เป้าหมายจะเปิดขึ้นโดยไม่มี O_TRUNC และ lseek () s จนถึงสิ้นสุด นั่นจะเป็นเพราะมันถูกเขียนขึ้นก่อนที่ธง O_APPEND open()ถูกบันทึก >>ตัวเองถูกแนะนำโดยบรรพบุรุษของมันที่เปลือกทอมสัน
Stéphane Chazelas

1
@ StéphaneChazelasนอกจากนี้ฉันค้นหา C เชลล์แหล่งที่มาสำหรับรุ่นต่าง ๆ และธง O_APPEND ไม่ได้แนะนำจนกระทั่ง 4.3BSD-Reno
Random832

มันบอกว่า "ราวกับว่า" ดังนั้นจึงไม่สามารถนำไปใช้ที่แตกต่างกัน (แต่ให้ผลที่สังเกตได้เหมือนกัน)? ดูเหมือนจะไม่ได้มาตรฐานต้องใช้ O_APPEND เพียงบางสิ่งที่มีพฤติกรรม "ราวกับ"
โทมัส

1
@ โทมัสมันหมายความว่าคุณจะได้รับพฤติกรรมทั้งหมดที่บันทึกไว้สำหรับ O_APPEND ซึ่งหมายถึงการเปลี่ยนตำแหน่งในตอนท้ายของการเขียนทุกครั้ง "ราวกับว่า" เป็นเพียงการใช้คำฟุ่มเฟือยมาตรฐานที่มีวัตถุประสงค์เพื่ออนุญาตให้มันจะถูกเปิดโดยวิธีการอื่นนอกเหนือจากการเรียกฟังก์ชั่น open () จริง ๆ บนแพลตฟอร์มที่ไม่ใช่แบบดั้งเดิม - ยูนิกซ์
Random832

+1 สำหรับแสดงว่าพฤติกรรมนี้อยู่ในมาตรฐาน
เปรม

32

หากมองในแหล่งที่มามันจะใช้ O_APPEND สำหรับ bash 4.3.30 ในmake_cmd.cบรรทัด 710-713 อ่าน:

case r_appending_to:                /* >>foo */
case r_append_err_and_out:          /* &>> filename */
  temp->flags = O_APPEND | O_WRONLY | O_CREAT;
  break;

+1 สำหรับการแสดงคำตอบจากมุมมองซอร์สโค้ด
เปรม

19

ลองตรวจสอบว่าการใช้straceระบบไฟล์โลคอล (ไม่ใช่ NFS):

$ strace -eopen -- bash -c "echo foo >> /tmp/testfile000" 2>&1 | grep /tmp/testfile000
open("/tmp/testfile000", O_WRONLY|O_CREAT|O_APPEND, 0666) = 3

$ strace -eopen -- bash -c "echo foo > /tmp/testfile000" 2>&1 | grep /tmp/testfile000
open("/tmp/testfile000", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3

เปลือกหอยอื่น ๆ , คือdash, dash, shของ busybox และmkshทำงานในลักษณะเดียวกัน

ตัวเลือก-e openหมายถึง-e trace=openการติดตามเฉพาะการopen()เรียกของระบบ

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