TL; DR
Відкрийте свій файл журналу в режимі додавання :
cmd >> log
Тоді ви можете сміливо усікати його за допомогою:
: > log
Деталі
З оболонкою, що нагадує Борну, є три основні способи, яким файл може бути відкритий для запису. У режимі лише для запису ( >) читайте + пишете ( <>) або додайте (і лише для запису >>) режиму.
У перших двох ядрах запам'ятовується поточне положення, яке ви (я маю на увазі, відкритий опис файлу , який ділиться всіма дескрипторами файлів, які дублювали або успадковували його шляхом виведення з того, на якому ви відкрили файл). файл.
Коли ви робите:
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
Це означає, що ви не можете вкоротити файл, який був відкритий у режимі лише для запису (і це те саме для читання + запису ), як якщо б ви це зробили, процеси, у яких були відкриті дескриптори файлів, залишать символи NUL на початку файл (ті, крім ОС / 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
Це також безпечніше, як якщо два процеси помилково відкрили (таким чином) файл (як, наприклад, якщо ви запустили два екземпляри одного демона), їх вихід не перезапише один одного.
На останніх версіях Linux ви можете перевірити поточну позицію та чи був відкритий дескриптор файлу в режимі додавання , переглянувши /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 або восьмеричний 02000)
Отже, оболонка >>відкриває файл з O_WRONLY|O_APPEND(і 0100000 тут є O_LARGEFILE, що не має відношення до цього питання), поки >є O_WRONLYлише (і <>є O_RDWRлише).
Якщо ви робите:
sudo lsof -nP +f g | grep ,AP
для пошуку файлів, відкритих за допомогою O_APPEND, ви знайдете більшість файлів журналів, які зараз відкриті для запису у вашій системі.