รักษาสิทธิ์ของไฟล์ (หรือเรียกคืน) เมื่อทำการแทนที่ไฟล์


11

ฉันมีคำสั่งที่ยอมรับไฟล์เป็นอาร์กิวเมนต์ปรับเปลี่ยนไฟล์จากนั้นเขียนไปยังชื่อไฟล์ที่ระบุในอาร์กิวเมนต์ที่สอง ฉันจะเรียกโปรแกรมmodifyfileนั้น

ฉันอยากให้มันทำงาน "แทนที่" ดังนั้นฉันจึงเขียนเชลล์สคริป (ทุบตี) ที่แก้ไขมันเป็นไฟล์ชั่วคราวจากนั้นย้ายมันกลับมา:

TMP=`mktemp`
modifyfile "$original" "$TMP"
mv -v "$TMP" "$original"

นี่เป็นผลข้างเคียงที่โชคร้ายของการทำลายการอนุญาตในไฟล์นี้ ไฟล์จะถูกสร้างขึ้นใหม่โดยมีการอนุญาตเริ่มต้น

มีวิธีบอกให้mvคำสั่งเขียนทับปลายทางโดยไม่เปลี่ยนการอนุญาตหรือไม่? หรือจะมีวิธีบันทึกผู้ใช้กลุ่มและการอนุญาตจากต้นฉบับและกู้คืนได้หรือไม่

คำตอบ:


10

แทนการใช้เพียงแค่เปลี่ยนเส้นทางmv catตัวอย่างเช่น:

TMP=$(mktemp)
modifyfile "$original" "$TMP"
cat "$TMP" > "$original"

สิ่งนี้จะเขียนทับ$originalเนื้อหาของ$TMPโดยไม่ต้องแตะอะไรที่ระดับไฟล์


ไม่เป็นปัญหาหรือไม่หากบางโปรแกรมมีตัวจัดการไฟล์ที่เปิดอยู่กับไฟล์
Martin von Wittich

2
จากนั้นฉันก็ต้องทำrm "$TMP"เช่นกัน แต่ดูเหมือนจะทำในสิ่งที่ฉันต้องการ
Stephen Ostermiller

@Martinvon ซึ่งอาจเป็นปัญหาหากคุณใช้งานmvแทน ฉันไม่เห็นวิธีในการแก้ปัญหานั้น
strugee

2
@MartinvonWittich ใช่ สร้างใหม่แล้วย้ายให้คุณเปลี่ยนอะตอมและไม่ส่งผลกระทบต่อโปรแกรมที่เปิดไฟล์ แต่เนื่องจากสร้างไฟล์ใหม่การเป็นเจ้าของไฟล์และสิทธิ์จะหายไป ตัดทอน - ที่มีอยู่แล้ว - เขียนเก็บรักษาสิทธิ์และความเป็นเจ้าของ แต่สูญเสียข้อมูลในกรณีที่เกิดความผิดพลาดและปัดพรมใต้พื้นของโปรแกรมที่เปิดไฟล์ คุณไม่สามารถรวมส่วนที่ดีของทั้งสองอย่างเข้าด้วยกัน
Gilles 'หยุดความชั่วร้าย'

1
@MartinvonWittich chownทำงานเป็น root เท่านั้น chmodและchgrpอาจทำงานได้หรือไม่ขึ้นอยู่กับการอนุญาตของผู้ใช้ ไม่คัดลอกคุณลักษณะอื่น ๆ เช่น ACL หรือแอตทริบิวต์เพิ่มเติมเฉพาะของระบบไฟล์
Gilles 'หยุดความชั่วร้าย'

10

มีสองวิธีในการแทนที่ไฟล์ด้วยเวอร์ชันใหม่:

  1. สร้างไฟล์ชั่วคราวด้วยเวอร์ชันใหม่จากนั้นย้ายไปไว้ที่เดิม

    • ข้อได้เปรียบ: หากโปรแกรมเปิดไฟล์นั้นก็จะอ่านเนื้อหาเก่าหรือเนื้อหาใหม่ขึ้นอยู่กับว่าเปิดไฟล์ก่อนหรือหลังการย้าย ไม่มีการมิกซ์
    • ข้อได้เปรียบ: ในกรณีที่เกิดความผิดพลาดเนื้อหาเก่าจะถูกเก็บไว้
    • ข้อเสีย: เนื่องจากไฟล์ใหม่ถูกสร้างขึ้นคุณลักษณะของไฟล์ (ความเป็นเจ้าของสิทธิ์ ฯลฯ ) จะไม่ถูกสงวนไว้
  2. เขียนทับไฟล์เก่าแทน

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

หากคุณสามารถใช้วิธีที่ 1 cp -p --attributes-onlyแต่ทำซ้ำครั้งแรกแอตทริบิวต์ของไฟล์ต้นฉบับด้วย สิ่งนี้ต้องใช้ GNU coreutils (เช่น Linux ที่ไม่ได้ฝังตัวหรือมีสภาพแวดล้อมคล้าย Linux เพียงพอ) หากคุณcpไม่มี--attributes-onlyให้ละเว้นตัวเลือกนี้: มันจะใช้งานได้ แต่มันจะทำซ้ำข้อมูลเช่นกัน

tmp=$(mktemp)
cp -p --attributes-only "$original" "$tmp"
modifyfile "$original" "$tmp"
mv -f "$tmp" "$original"

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

  • ทำให้หน้าต่างในระหว่างที่ไฟล์จะไม่สมบูรณ์มีขนาดเล็กที่สุด เตรียมข้อมูลก่อนในไฟล์ชั่วคราวจากนั้นคัดลอกลงในสถานที่
  • ทำสำเนาสำรองของไฟล์เก่าก่อน

tmp=$(mktemp)
backup="${original}~"
modifyfile "$original" "$tmp"
cp -p "$original" "$backup"
cp -f "$tmp" "$original"

คำตอบที่ดี! ปัจจุบันผมขอแนะนำให้ใช้อาร์กิวเมนต์--attributes เดียวกับซีพีคำสั่งในวิธีที่ 1 ด้วยวิธีนี้การcp -p --attributes-only "$original" "$tmp"จะไม่ใช้ทรัพยากรเพื่อคัดลอกเนื้อหาของไฟล์ ฉันไม่พบอาร์กิวเมนต์นี้ที่เพิ่มเข้ามา
Marcelo Barros

@MarceloBarros มันถูกเพิ่มเข้ามาใน GNU coreutils 8.6 ปล่อยตัว 2010-10-15 ดังนั้นวันนี้ถ้าคุณมี CoreUtils GNU คุณควรจะมีมัน ยังไม่มีสิ่งเช่นนี้กับcpการใช้งานอื่น ๆ
Gilles 'หยุดชั่วร้าย'

5

หลังจากการอภิปรายของเราเกี่ยวกับคำตอบแรกฉันเสนอคำตอบที่แตกต่าง:

TMP="$(mktemp "$original".XXXXXXXXXX)"
modifyfile "$original" "$TMP"
chmod --reference="$original" "$TMP"
chown --reference="$original" "$TMP"
mv -f "$TMP" "$original"

หมายเหตุ:

  • ผมใช้$originalในmktempแม่แบบเพื่อให้แน่ใจว่าแฟ้มชั่วคราวไม่ได้อยู่ในแต่ในโฟลเดอร์เดียวกันกับ/tmp $originalฉันเชื่อว่าถ้า/tmpติดตั้งบนระบบไฟล์อื่นการดำเนินการจะไม่เป็นแบบอะตอมอีกต่อไป
  • mktempตอนนี้ผลลัพธ์ของการอ้างถึงในกรณีที่มีช่องว่าง
  • ฉันใช้$()แทน `` เพราะฉันเห็นว่ามันสะอาดกว่า
  • ch{mod,own} --referenceจะใช้ในการโอนสิทธิ์ของการ$original $TMPหากใครบางคนมีแนวคิดเพิ่มเติมว่าข้อมูลเมตาใดที่สามารถและควรจะถ่ายโอนโปรดแก้ไขโพสต์ของฉันและเพิ่ม
  • โอ้ดีต้องใช้สิทธิ์รูทตามที่ Gilles ชี้ให้เห็น ฉันจะไม่ทิ้งเรื่องนี้ตอนที่ฉันเขียนมัน: P
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.