Очистить файл во время использования в Linux

Я пытаюсь очистить файл в linux во время использования, это файл журнала, поэтому он постоянно написан. Прямо сейчас я использовал:

echo -n > filename

или

cat /dev/null > filename

но все это создает пустой файл с символом новой строки (или странным символом, который я могу видеть как ^ @^ @^ @^ @^ @^ @^ @^ @^ @^ @^ @^.. на vi), и я должен удалить вручную с помощью vi и dd первой строки, а затем сохранить.

Если я не использую vi adn dd, я не могу манипулировать файлом с помощью grep, но мне нужна автоматическая процедура, которую я могу написать в оболочке script.

Идеи?

Ответ 1

Этого должно быть достаточно, чтобы удалить файл:

> file

Однако другие методы, о которых вы говорили, вы также должны работать. Если вы видите странные символы, то они записываются в файл с помощью чего-то другого - скорее всего, какой бы процесс не регистрировался там.

Ответ 2

Все происходит довольно просто: вы выгружаете файл.

Почему он заполнен ^@ s, тогда вы спрашиваете? Ну, в очень реальном смысле это не так. Он не содержит этих странных символов. Он имеет "отверстие".

Программа, которая записывает в файл, записывает файл, который был открыт с помощью O_WRONLY (или, возможно, O_RDWR), но не O_APPEND. Эта программа написала, скажем, 65536 байт в файл в момент, когда вы выгрузили файл с помощью cp /dev/null filename или : > filename или некоторой подобной команды.

Теперь программа переходит к write другому фрагменту данных (скажем, 4096 или 8192 байта). Где будут записываться эти данные? Ответ: "при текущем смещении поиска в базовом дескрипторе файла". Если для программы, используемой O_APPEND, write будет, по сути, предшествует вызов lseek, который выполнил "поиск текущего конца файла, то есть текущую длину файла". Когда вы обрезаете файл, который "текущий конец файла" станет нулевым (файл станет пустым), чтобы поиск переместил смещение write в положение 0, и запись туда пошла бы. Но программа не использовала O_APPEND, поэтому нет операции "перепозиции" pre-write, а байты данных записываются с текущим смещением (что, опять же, мы утверждали, что оно выше 65536).

Теперь у вас есть файл, который не имеет данных в байтовых смещениях от 0 до 65535 включительно, за которыми следуют некоторые данные в байтовых смещениях с 65536 по 73727 (при условии, что write записывает 8192 байта). Эти "недостающие" данные являются "дыркой" в файле. Когда какая-то другая программа переходит к чтению файла, ОС притворяется, что там есть данные: все-нулевые байты.

Если программа, выполняющая операции write, не делает их на границах блоков, ОС фактически выделяет некоторые дополнительные данные (чтобы соответствовать записи в целые блоки) и обнулить ее. Эти нулевые байты не являются частью "дыры" (они являются реальными нулевыми байтами в файле), а обычным программам, которые не заглядывают за занавес в "Волшебника из страны Оз", "ноль-байты" и "нет" "нулевые" байты неразличимы.

Что вам нужно сделать, это изменить программу на использование O_APPEND или использовать библиотечные процедуры, такие как syslog, которые знают, как взаимодействовать с операциями чередования логов или, возможно, и то, и другое.

[Edit to add: не знаю, почему это неожиданно появилось на первой странице, и я ответил на вопрос с 2011 года...]

Ответ 3

Другим способом является следующее:

cp /dev/null the_file

Преимущество этого метода заключается в том, что он представляет собой единую команду, поэтому в случае необходимости доступа к sudo требуется только один sudo-вызов.

Ответ 4

Почему не просто :>filename?

(: является встроенным bash с тем же эффектом, что и /bin/true, и обе команды ничего не отгоняют)

Доказательство того, что он работает:

[email protected] ~ $ du t.txt
4       t.txt
[email protected] ~ $ :>t.txt
[email protected] ~ $ du t.txt
0       t.txt

Ответ 5

Если это файл журнала, то правильный способ сделать это - использовать logrotate. Как вы уже сказали, это не работает вручную.

Ответ 6

У меня нет оболочки linux здесь, чтобы попробовать ir, но попробуйте ли вы это сделать?

echo "" > file