Как сохранить последние 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 строк.

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

dorinand
источник
2
Нечто подобное rrdtool может быть более подходящим для хранения N записей (среди других показателей) с течением времени.
thrig
См. Также unix.stackexchange.com/a/147620/117549
Джефф Шаллер
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
iobender
источник
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

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

CLK
источник
Спасибо. Не могли бы вы объяснить мне шаг за шагом, что выполнить 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)регулярно выполнять резервное копирование файлов журналов, чтобы постепенно называть файлы, а затем удалять старые.

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

CSM
источник