Как сохранить последние 50 строк в лог-файле


22

Я пытаюсь сохранить последние 50 строк в моем файле, где я сохраняю температуру каждую минуту. Я использовал эту команду:

tail -n 50 /home/pi/Documents/test > /home/pi/Documents/test

Но результат - пустой тестовый файл. Я думал, он перечислит последние 50 строк тестового файла и вставит его в тестовый файл. Когда я использую эту команду:

tail -n 50 /home/pi/Documents/test > /home/pi/Documents/test2

это работает нормально. В файле test2 50 строк.

Кто-нибудь может объяснить мне, где проблема?


2
Нечто подобное rrdtool может быть более подходящим для хранения N записей (среди других показателей) с течением времени.
thrig


2
классическая проблема усечения
хайлем

Если вы используете python для генерации ваших логов, вам следует заглянуть в loggingмодуль
Уэйн Вернер,

Ответы:


30

Проблема в том, что ваша оболочка настраивает конвейер команд перед запуском команд. Дело не в «вводе и выводе», а в том, что содержимое файла уже удалено до того, как tail запустится. Это выглядит примерно так:

  1. Оболочка открывает >выходной файл для записи, обрезая его
  2. Оболочка настроена на использование файлового дескриптора 1 (для stdout) для этого вывода
  3. Оболочка выполняется tail.
  4. tailбегает, открывает /home/pi/Documents/testи ничего не находит там

Существуют различные решения, но главное - понять проблему, что на самом деле идет не так и почему.

Это произведет то, что вы ищете,

echo "$(tail -n 50 /home/pi/Documents/test)" > /home/pi/Documents/test

Пояснение:

  • $() называется подстановка команды, которая выполняет tail -n 50 /home/pi/Documents/test
  • кавычки сохраняют разрывы строк в выходных данных.
  • > /home/pi/Documents/testперенаправляет вывод echo "$(tail -n 50 /home/pi/Documents/test)"в тот же файл.

Спасибо, это отлично работает! У меня есть еще один вопрос. Не могли бы вы объяснить, как ваша процедура работает шаг за шагом?
Дорин и

1
Но почему в вашем случае bash не выполняется> первым? Я не понимаю, как bash обрабатывает команду. Кто-нибудь может объяснить?
Дорин и

1
Символ> находится в команде echo, поэтому он выполняется, когда команда echo начинает выполнение. Он не может начать выполнение до того, как будет написано. Подстановка переменных - это то, что пишет команда. Он запускает вложенную команду и создает команду echo, подставляя значение.
Jobermark

Когда я пытался использовать то же самое для файла журнала 44 ГБ, используя 5000 строк вместо 50, я получаю сообщение об ошибкеbash: xrealloc: cannot allocate 18446744071562067968 bytes
Carmageddon

8

Другое решение для перенаправления файла, сначала очищающее файл, заключается в использовании spongeиз moreutilsпакета следующим образом:

tail -n 50 /home/pi/Documents/test | sponge /home/pi/Documents/test

6

Это связано с тем, что bash обрабатывает перенаправление >первым, удаляя содержимое файла. Затем он выполняет команду. Если бы вы использовали >>, последние 50 строк были бы добавлены в конец того, что в настоящее время находится в файле. В этом случае вы бы повторили 50 одинаковых строк.

Команда работает, как и ожидалось, при перенаправлении в другой файл. Вот один из способов записать последние 50 строк файла в файл с таким же именем:

tail -50 /home/pi/Documents/test > /home/pi/Documents/test2 && mv /home/pi/Documents/test2 /home/pi/Documents/test

Это сначала записывает последние 50 строк во временный файл, который затем перемещается с помощью mvзамены исходного файла.

Как отмечено в комментариях, это не будет работать, если файл все еще открыт. Перемещение файла также создает новый индекс и может изменить владельца и разрешения. Лучший способ сделать это, используя временный файл:

tail -50 /home/pi/Documents/test > /home/pi/Documents/test2 ; cat /home/pi/Documents/test2 > /home/pi/Documents/test

Временный файл также может быть удален, хотя каждый раз, когда это происходит, его содержимое будет перезаписываться.


Спасибо. Не могли бы вы объяснить мне шаг за шагом, что выполнить Bash? Я не могу представить, как это работает.
Дорин и

tail -50 /home/pi/Documents/test >/tmp/foo && cat /tmp/foo >/home/pi/Documents/test
Стив

1
обратите внимание, что это не сработает, если файл журнала все еще открыт процессом регистрации (который продолжит запись в исходный удаленный файл). tempfile + move приводит к новому иноду (нарушающему любые жесткие ссылки) и, возможно, другому владельцу или привилегии. tail ... > temp ; cat temp > orig ; rm -f tempработает.
Cas

4

Поскольку вы видели основную проблему с перенаправлением оболочки, вот альтернативный способ сокращения файла до последних 50 строк:

file=/path/to/the/file
n=$(( $(wc -l < "$file") - 50 ))
[[ $n -gt 0 ]] && sed -i 1,${n}d "$file"

Тяжелую работу выполняет (GNU) sed с -iфункцией «редактирования на месте», которая работает под прикрытием, создавая выходные данные во временном файле. Остальные строки настраивают математику для работы sed, а именно:

  1. посчитать строки в файле ( wc), затем вычесть 50; назначьте это n.
  2. если n положительно, выполните команду sed, чтобы удалить строки с 1 по n.

4
printf '%s\n' '1,$-50d'   w | ed -s /home/pi/Documents/tes

printfиспользуется для передачи команд (по одной на строку) в ed. Эти edкоманды являются:

  • 1,$-50d - удалить все, кроме последних 50 строк
  • w - записать измененный файл обратно на диск

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

Кроме того, в отличие от большинства форм редактирования «на месте» (которые обычно имитируют редактирование «на месте» путем создания временного файла с последующим переименованием его поверх оригинала), edфактически редактирует исходный файл - поэтому он сохраняет тот же индекс ( а владелец, группа и права доступа - tempfile + mv всегда изменяет inode и может изменять другие в зависимости от обстоятельств).


4

С другой стороны, вы можете logrotate(8)регулярно выполнять резервное копирование файлов журналов, чтобы постепенно называть файлы, а затем удалять старые.

Вот как управляются основные системные журналы, чтобы они не росли слишком долго.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.