TL; DR
เปิดไฟล์บันทึกของคุณในโหมดผนวก :
cmd >> log
จากนั้นคุณสามารถตัดทอนได้อย่างปลอดภัยด้วย:
: > log
รายละเอียด
ด้วยเชลล์คล้ายบอร์นมี 3 วิธีหลักที่ไฟล์สามารถเปิดสำหรับการเขียนได้ ในโหมดเขียนอย่างเดียว ( >) อ่าน + เขียน ( <>) หรือผนวก (และเขียนอย่างเดียว>>) โหมด
ในสองคนแรกเคอร์เนลจะจดจำตำแหน่งปัจจุบันของคุณ (โดยคุณฉันหมายถึงคำอธิบายไฟล์แบบเปิดที่ใช้ร่วมกันโดยตัวอธิบายไฟล์ทั้งหมดที่มีการทำซ้ำหรือสืบทอดโดยการฟอร์กจากไฟล์ที่คุณเปิดไฟล์) ไฟล์.
เมื่อคุณทำ:
cmd > log
logมีการเปิดในการเขียนเท่านั้นโหมดโดยเปลือกสำหรับ stdout cmdของ
cmd(กระบวนการเริ่มต้นเกิดขึ้นโดยเชลล์และลูก ๆ ที่เป็นไปได้ทั้งหมด) เมื่อเขียนไปยัง stdout ของพวกเขาเขียนที่ตำแหน่งเคอร์เซอร์ปัจจุบันที่ถือโดยคำอธิบายไฟล์เปิดที่พวกเขาแบ่งปันในไฟล์นั้น
ตัวอย่างเช่นหากcmdเริ่มต้นเขียนzzzตำแหน่งจะอยู่ที่ไบต์ออฟเซ็ต 4 ลงในไฟล์และในครั้งถัดไปcmdหรือลูก ๆ ของมันเขียนไปยังไฟล์นั่นคือที่ที่ข้อมูลจะถูกเขียนโดยไม่คำนึงว่าไฟล์นั้นเติบโตหรือหดตัวในช่วงเวลาใด .
หากไฟล์มีการหดตัวอย่างเช่นหากไฟล์ถูกตัดทอนด้วย
: > log
และcmdเขียนข้อมูลxxเหล่านั้นxxจะถูกเขียนที่ออฟเซ็ต4และอักขระ 3 ตัวแรกจะถูกแทนที่ด้วยอักขระ NUL
$ exec 3> log # open file on fd 3.
$ printf zzz >&3
$ od -c log
0000000 z z z
0000003
$ printf aaaa >> log # other open file description -> different cursor
$ od -c log
0000000 z z z a a a a
0000007
$ printf bb >&3 # still write at the original position
$ od -c log
0000000 z z z b b a a
0000007
$ : > log
$ wc log
0 0 0 log
$ printf x >&3
$ od -c log
0000000 \0 \0 \0 \0 \0 x
0000006
นั่นหมายความว่าคุณไม่สามารถตัดไฟล์ที่เปิดในโหมดเขียนอย่างเดียว (และเป็นแบบเดียวกันสำหรับอ่าน + เขียน ) ราวกับว่าคุณทำกระบวนการที่เปิดไฟล์ descriptors ไว้บนไฟล์จะทำให้อักขระ NUL อยู่ที่จุดเริ่มต้นของ ไฟล์ (ยกเว้นใน OS / X มักจะไม่ใช้พื้นที่บนดิสก์ แต่จะเป็นไฟล์แบบกระจาย)
(และคุณจะสังเกตเห็นว่าแอปพลิเคชันส่วนใหญ่ทำเช่นนั้นเมื่อพวกเขาเขียนไปยังล็อกไฟล์) คุณควรเปิดไฟล์ในโหมดต่อท้าย :
cmd >> log
หรือ
: > log && cmd >> log
หากคุณต้องการเริ่มไฟล์เปล่า
ในโหมดต่อท้ายการเขียนทั้งหมดจะทำที่ส่วนท้ายของไฟล์โดยไม่คำนึงถึงตำแหน่งที่การเขียนล่าสุด:
$ exec 4>> log
$ printf aa >&4
$ printf x >> log
$ printf bb >&4
$ od -c log
0000000 a a x b b
0000005
$ : > log
$ printf cc >&4
$ od -c log
0000000 c c
0000002
นั่นเป็นวิธีที่ปลอดภัยกว่าเช่นกันหากกระบวนการสองกระบวนการเปิด (โดยวิธีนี้) ไฟล์โดยไม่ได้ตั้งใจ (เช่นถ้าคุณเริ่มต้นอินสแตนซ์ที่สองของ daemon เดียวกัน) เอาต์พุตของพวกเขาจะไม่เขียนทับกัน
บน Linux เวอร์ชันล่าสุดคุณสามารถตรวจสอบตำแหน่งปัจจุบันและระบุว่า file descriptor เปิดในโหมดต่อท้ายหรือไม่โดยดูที่/proc/<pid>/fdinfo/<fd>:
$ cat /proc/self/fdinfo/4
pos: 2
flags: 0102001
หรือด้วย:
$ lsof +f G -p "$$" -ad 4
COMMAND PID USER FD TYPE FILE-FLAG DEVICE SIZE/OFF NODE NAME
zsh 4870 root 4w REG 0x8401;0x0 252,18 2 59431479 /home/chazelas/log
~# lsof +f g -p "$$" -ad 4
COMMAND PID USER FD TYPE FILE-FLAG DEVICE SIZE/OFF NODE NAME
zsh 4870 root 4w REG W,AP,LG 252,18 2 59431479 /home/chazelas/log
แฟล็กเหล่านั้นสอดคล้องกับแฟล็กO ..._ ที่ส่งผ่านไปยังการopenเรียกระบบ
$ gcc -E - <<< $'#include <fcntl.h>\nO_APPEND O_WRONLY' | tail -n1
02000 01
( O_APPENDคือ 0x400 หรือ octal 02000)
ดังนั้นเชลล์ของ>>เปิดไฟล์ด้วยO_WRONLY|O_APPEND(และ 0100000 นี่คือ O_LARGEFILE ซึ่งไม่เกี่ยวข้องกับคำถามนี้) ในขณะที่>เป็นO_WRONLYเพียง (และ<>เป็นO_RDWRเท่านั้น)
ถ้าคุณทำ:
sudo lsof -nP +f g | grep ,AP
เพื่อค้นหาไฟล์ที่เปิดด้วยO_APPENDคุณจะพบไฟล์บันทึกส่วนใหญ่ที่เปิดอยู่สำหรับการเขียนบนระบบของคุณ