TL; DR
Otwórz plik dziennika w trybie dołączania :
cmd >> log
Następnie możesz bezpiecznie obciąć go za pomocą:
: > log
Detale
Dzięki powłoce podobnej do Bourne'a istnieją 3 główne sposoby otwierania pliku do zapisu. W trybie tylko do zapisu ( >), odczytu + zapisu ( <>) lub dołączania (i tylko zapisu >>).
W pierwszych dwóch jądrach zapamiętuje bieżącą pozycję, którą ty (mam na myśli, opis otwartego pliku , udostępniony przez wszystkie deskryptory plików, które zduplikowały lub odziedziczyły go, przechodząc od tego, w którym otworzyłeś plik) jesteś w plik.
Kiedy to zrobisz:
cmd > log
logjest otwarty w trybie tylko do zapisu przez powłokę dla standardowego wejścia cmd.
cmd(jego początkowy proces został zaszczepiony przez powłokę i wszystkie możliwe dzieci) podczas pisania na standardowe wyjście, pisz w bieżącej pozycji kursora utrzymywanej przez otwarty opis pliku, który udostępniają w tym pliku.
Na przykład, jeśli cmdpoczątkowo zapisuje zzz, pozycja będzie w przesunięciu bajtu 4 do pliku, a następnym razem cmdlub jego dzieci zapisują do pliku, to tam zapisywane będą dane bez względu na to, czy plik urósł, czy zmniejszył się w tym przedziale .
Jeśli plik się skurczył, na przykład jeśli został obcięty za pomocą
: > log
i cmdpisze xx, xxzostaną one zapisane z przesunięciem 4, a pierwsze 3 znaki zostaną zastąpione znakami 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
Oznacza to, że nie można obciąć pliku, który został otwarty w trybie tylko do zapisu (i to samo dotyczy odczytu i zapisu ), tak jak w przypadku procesów, w których deskryptory plików były otwarte na pliku, pozostawi znaki NUL na początku plik (te, z wyjątkiem OS / X, zwykle nie zajmują miejsca na dysku, stają się rzadkimi plikami).
Zamiast tego (a zauważysz, że większość aplikacji robi to podczas zapisywania plików dziennika), powinieneś otworzyć plik w trybie dołączania :
cmd >> log
lub
: > log && cmd >> log
jeśli chcesz zacząć od pustego pliku.
W trybie dołączania wszystkie zapisy są wykonywane na końcu pliku, niezależnie od tego, gdzie był ostatni zapis:
$ 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
Jest to również bezpieczniejsze, ponieważ jeśli dwa procesy otworzyły (w ten sposób) plik przez pomyłkę (na przykład, jeśli uruchomiłeś dwa wystąpienia tego samego demona), ich dane wyjściowe się nie zastąpią.
W najnowszych wersjach systemu Linux można sprawdzić bieżącą pozycję i sprawdzić, czy deskryptor pliku został otwarty w trybie dołączania , patrząc na /proc/<pid>/fdinfo/<fd>:
$ cat /proc/self/fdinfo/4
pos: 2
flags: 0102001
Lub z:
$ 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
Te flagi odpowiadają flagom O ..._ przekazanym do openwywołania systemowego.
$ gcc -E - <<< $'#include <fcntl.h>\nO_APPEND O_WRONLY' | tail -n1
02000 01
( O_APPENDjest 0x400 lub ósemkowy 02000)
Więc powłoka >>otwiera plik za pomocą O_WRONLY|O_APPEND(a 0100000 to O_LARGEFILE, co nie ma związku z tym pytaniem), podczas gdy >jest O_WRONLYtylko (i <>jest O_RDWRtylko).
Jeśli wykonasz:
sudo lsof -nP +f g | grep ,AP
Aby wyszukać pliki otwarte za pomocą O_APPEND, znajdziesz większość plików dziennika aktualnie otwartych do zapisu w systemie.