TL; DR
Buka file log Anda dalam mode tambahkan :
cmd >> log
Kemudian, Anda dapat memotongnya dengan aman dengan:
: > log
Detail
Dengan shell seperti Bourne, ada 3 cara utama file dapat dibuka untuk ditulis. Di tulis saja ( >
), baca + tulis ( <>
) atau tambahkan (dan tulis saja,>>
mode ).
Pada dua yang pertama, kernel mengingat posisi Anda saat ini (maksud Anda, deskripsi file yang terbuka , dibagikan oleh semua deskriptor file yang telah menggandakan atau mewarisi itu dengan mem-forking dari yang Anda buka file) berada di dalam mengajukan.
Saat kamu melakukan:
cmd > log
log
terbuka dalam mode tulis saja oleh shell untuk stdout cmd
.
cmd
(proses awalnya dihasilkan oleh shell dan semua anak yang mungkin) saat menulis ke stdout mereka, menulis pada posisi kursor saat ini yang dipegang oleh deskripsi file terbuka yang mereka bagi pada file itu.
Misalnya, jika cmd
pada awalnya menulis zzz
, posisi byte akan diimbangi 4 ke dalam file, dan waktu berikutnya cmd
atau anak-anaknya menulis ke file, di situlah data akan ditulis terlepas dari apakah file telah tumbuh atau menyusut dalam interval .
Jika file telah menyusut, misalnya jika telah terpotong dengan a
: > log
dan cmd
menulis xx
, itu xx
akan ditulis di offset 4
, dan 3 karakter pertama akan digantikan oleh karakter 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
Itu berarti Anda tidak dapat memotong file yang telah terbuka dalam mode tulis-saja (dan itu sama untuk baca + tulis ) seolah-olah Anda melakukannya, proses yang memiliki deskriptor file terbuka pada file, akan meninggalkan karakter NUL di awal file (itu, kecuali pada OS / X, biasanya tidak mengambil ruang pada disk sekalipun, mereka menjadi file jarang).
Alih-alih (dan Anda akan melihat sebagian besar aplikasi melakukannya ketika mereka menulis untuk mencatat file), Anda harus membuka file dalam mode append :
cmd >> log
atau
: > log && cmd >> log
jika Anda ingin memulai pada file kosong.
Dalam mode tambahkan, semua penulisan dilakukan di akhir file, terlepas dari di mana penulisan terakhir:
$ 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
Itu juga lebih aman seolah-olah dua proses membuka (dengan cara itu) file secara tidak sengaja (seperti misalnya jika Anda sudah memulai dua contoh dari daemon yang sama), hasilnya tidak akan saling menimpa.
Pada versi Linux terbaru, Anda dapat memeriksa posisi saat ini dan apakah deskriptor file telah terbuka dalam mode penambahan dengan melihat /proc/<pid>/fdinfo/<fd>
:
$ cat /proc/self/fdinfo/4
pos: 2
flags: 0102001
Atau dengan:
$ 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
Mereka bendera sesuai dengan O ..._ bendera diteruskan ke open
system call.
$ gcc -E - <<< $'#include <fcntl.h>\nO_APPEND O_WRONLY' | tail -n1
02000 01
( O_APPEND
adalah 0x400 atau oktal 02000)
Jadi shell >>
membuka file dengan O_WRONLY|O_APPEND
(dan 0.100.000 di sini adalah O_LARGEFILE yang tidak relevan dengan pertanyaan ini) sementara >
adalah O_WRONLY
hanya (dan <>
ini O_RDWR
hanya).
Jika Anda melakukan:
sudo lsof -nP +f g | grep ,AP
untuk mencari file yang terbuka O_APPEND
, Anda akan menemukan sebagian besar file log saat ini terbuka untuk ditulis di sistem Anda.