TL; DR
Apri il tuo file di registro in modalità append :
cmd >> log
Quindi, puoi troncarlo in sicurezza con:
: > log
Dettagli
Con una shell tipo Bourne, ci sono 3 modi principali in cui un file può essere aperto per la scrittura. In modalità sola scrittura ( >), leggi + scrivi ( <>) o aggiungi (e sola scrittura, >>).
Nei primi due, il kernel ricorda la posizione corrente in cui tu (da parte tua, intendo, la descrizione del file aperto , condivisa da tutti i descrittori di file che l'hanno duplicato o ereditato biforcando da quello su cui hai aperto il file) sei nel file.
Quando lo fai:
cmd > log
logè aperto in modalità di sola scrittura dalla shell per lo stdout di cmd.
cmd(il suo processo iniziale generato dalla shell e da tutti i possibili figli) quando si scrive sul loro stdout, scrivere nella posizione corrente del cursore mantenuta dalla descrizione del file aperto che condividono su quel file.
Ad esempio, se cmdinizialmente scrive zzz, la posizione sarà all'offset di byte 4 nel file e la volta successiva cmdo i suoi figli scriveranno nel file, è lì che i dati verranno scritti indipendentemente dal fatto che il file sia cresciuto o ridotto nell'intervallo .
Se il file si è ridotto, ad esempio se è stato troncato con a
: > log
e cmdscrive xx, quelli xxsaranno scritti in offset 4e i primi 3 caratteri saranno sostituiti da caratteri 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
Ciò significa che non è possibile troncare un file che è stato aperto in modalità di sola scrittura (ed è lo stesso per read + write ) come in caso contrario, i processi con descrittori di file aperti sul file, lasceranno i caratteri NUL all'inizio del file (quelli, tranne su OS / X, di solito non occupano spazio sul disco, ma diventano file sparsi).
Invece (e noterai che la maggior parte delle applicazioni lo fa quando scrivono nei file di registro), dovresti aprire il file in modalità append :
cmd >> log
o
: > log && cmd >> log
se vuoi iniziare con un file vuoto.
In modalità append, tutte le scritture vengono eseguite alla fine del file, indipendentemente da dove sia stata l'ultima scrittura:
$ 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
È anche più sicuro che se due processi hanno aperto (in quel modo) il file per errore (come ad esempio se hai avviato due istanze dello stesso demone), il loro output non si sovrascriverà a vicenda.
Nelle versioni recenti di Linux, puoi controllare la posizione corrente e se un descrittore di file è stato aperto in modalità append guardando /proc/<pid>/fdinfo/<fd>:
$ cat /proc/self/fdinfo/4
pos: 2
flags: 0102001
O con:
$ 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
Tali flag corrispondono ai flag O ..._ passati alla openchiamata di sistema.
$ gcc -E - <<< $'#include <fcntl.h>\nO_APPEND O_WRONLY' | tail -n1
02000 01
( O_APPENDè 0x400 o 02000 ottale)
Quindi la shell >>apre il file con O_WRONLY|O_APPEND(e 0100000 qui è O_LARGEFILE che non è rilevante per questa domanda) mentre >è O_WRONLYsolo (ed <>è O_RDWRsolo).
Se fai un:
sudo lsof -nP +f g | grep ,AP
per cercare i file aperti O_APPEND, troverai la maggior parte dei file di registro attualmente aperti per la scrittura sul tuo sistema.