TL; DR
Mở tệp nhật ký của bạn ở chế độ chắp thêm :
cmd >> log
Sau đó, bạn có thể cắt nó một cách an toàn với:
: > log
Chi tiết
Với trình bao giống như Bourne, có 3 cách chính để mở tệp. Trong chỉ ghi ( >), đọc + write ( <>) hoặc chắp thêm (và chỉ ghi,>> ).
Trong hai phần đầu, kernel ghi nhớ vị trí hiện tại của bạn (ý bạn là, mô tả tệp đang mở , được chia sẻ bởi tất cả các mô tả tệp đã sao chép hoặc kế thừa nó bằng cách chuyển từ vị trí bạn đã mở tệp trên) tập tin.
Khi bạn làm:
cmd > log
logđược mở trong chế độ chỉ ghi bởi trình bao cho thiết bị xuất chuẩn của cmd.
cmd(quá trình ban đầu của nó được sinh ra bởi shell và tất cả các con có thể) khi viết vào thiết bị xuất chuẩn của chúng, hãy viết ở vị trí con trỏ hiện tại được giữ bởi mô tả tệp mở mà chúng chia sẻ trên tệp đó.
Chẳng hạn, nếu cmdban đầu ghi zzz, vị trí sẽ ở byte bù 4 vào tệp và lần sau cmdhoặc con của nó ghi vào tệp, đó là nơi dữ liệu sẽ được ghi bất kể tệp đã tăng hay giảm trong khoảng thời gian .
Nếu tập tin bị thu hẹp, ví dụ nếu nó đã bị cắt bằng
: > log
và cmdviết xx, những cái đó xxsẽ được viết ở offset 4, và 3 ký tự đầu tiên sẽ được thay thế bằng các ký tự 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
Điều đó có nghĩa là bạn không thể cắt một tệp đã được mở ở chế độ chỉ ghi (và tương tự đối với đọc + ghi ) như khi bạn thực hiện, các quy trình có mô tả tệp mở trên tệp, sẽ để lại các ký tự NUL ở đầu tệp (những tệp, ngoại trừ trên OS / X, thường không chiếm dung lượng trên đĩa, chúng trở thành các tệp thưa thớt).
Thay vào đó (và bạn sẽ nhận thấy hầu hết các ứng dụng làm điều đó khi chúng ghi vào tệp nhật ký), bạn nên mở tệp ở chế độ chắp thêm :
cmd >> log
hoặc là
: > log && cmd >> log
nếu bạn muốn bắt đầu trên một tập tin trống.
Trong chế độ chắp thêm, tất cả các ghi được thực hiện ở cuối tệp, bất kể nơi ghi cuối cùng là:
$ 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
Điều đó cũng an toàn hơn nếu hai quá trình mở (theo cách đó) tệp bị nhầm (ví dụ: nếu bạn đã bắt đầu hai phiên bản của cùng một trình nền), đầu ra của chúng sẽ không ghi đè lên nhau.
Trên các phiên bản gần đây của Linux, bạn có thể kiểm tra vị trí hiện tại và liệu mô tả tệp đã được mở trong chế độ chắp thêm hay chưa bằng cách xem /proc/<pid>/fdinfo/<fd>:
$ cat /proc/self/fdinfo/4
pos: 2
flags: 0102001
Hoặc với:
$ 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
Các cờ đó tương ứng với các cờ O ..._ được truyền cho lệnh opengọi hệ thống.
$ gcc -E - <<< $'#include <fcntl.h>\nO_APPEND O_WRONLY' | tail -n1
02000 01
( O_APPENDlà 0x400 hoặc bát phân 02000)
Vì vậy, các vỏ của >>mở file với O_WRONLY|O_APPEND(và 0.100.000 đây là O_LARGEFILE mà không liên quan đến câu hỏi này) trong khi >là O_WRONLYduy nhất (và <>là O_RDWRduy nhất).
Nếu bạn làm một:
sudo lsof -nP +f g | grep ,AP
để tìm kiếm các tệp đang mở O_APPEND, bạn sẽ tìm thấy hầu hết các tệp nhật ký hiện đang mở để ghi trên hệ thống của mình.