Как сохранить только последние n строк файла журнала?

. Вы можете использовать Командная строка ssh для запуска сервера SOCKS, который будет подключаться к указанному вами хосту:

ssh -D 2001 user@host.com

Это запустит сервер SOCKS на порту 2001, который будет направлять запросы на host.com. Они называют эту функцию «динамической переадресацией портов на уровне приложения».

Еще:

19
28.09.2016, 20:56
7 ответов

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

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

Ниже также удаляются пустые строки, если они существуют в конце файла журнала (из-за поведения BASH, оценивающего «$ (tail -1000 test.log)» ), поэтому не дает действительно 100% точное усечение во всех сценариях, но в зависимости от вашей ситуации может быть достаточно.

$ wc -l myscript.log
475494 myscript.log

$ echo "$(tail -1000 myscript.log)" > myscript.log

$ wc -l myscript.log
1000 myscript.log
47
27.01.2020, 19:44

Утилита sponge предназначена именно для этого случая. Если он у вас установлен, то ваши две строчки могут быть записаны:

tail -n 1000 myscript.log | sponge myscript.log

Обычно чтение из файла одновременно с записью в него ненадежно. sponge решает эту проблему, не записывая в myscript.log , пока tail не закончит его чтение и не завершит конвейер.

Установить

Чтобы установить sponge в системе, подобной Debian:

apt-get install moreutils

Чтобы установить sponge в системе RHEL / CentOS, добавьте репозиторий EPEL, а затем выполните:

yum install moreutils

Документация

Из man sponge :

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

32
27.01.2020, 19:44

определенно "хвост + мв" намного лучше! Но для gnu sed мы можем попробовать

sed -i -e :a -e '$q;N;101,$D;ba' log
5
27.01.2020, 19:44

Для записи, с помощью ed вы можете сделать что-то вроде

ed -s infile <<\IN
0r !tail -n 1000 infile
+1,$d
,p
q
IN

Это открывает infile и r вводит вывод tail -n 1000 infile (т.е. вставляет этот вывод перед 1-й строкой), а затем удаляет то, что изначально было 1-й строкой, до конца файла. Замените , p на w , чтобы отредактировать файл на месте.
Имейте в виду, что решения ed не подходят для больших файлов.

3
27.01.2020, 19:44

В сценарии вы можете реализовать логику ротации журналов. Выполните всю регистрацию с помощью функции:

log()
{
   ...
}

Эта функция, во-первых, делает что-то вроде:

printf "%s\n" "$*" >> logfile

затем проверяет размер файла или каким-то образом решает, что файл требует поворота. В этот момент файл logfile.1 , если он существует, удаляется, файл logfile.0 , если он существует, переименовывается в logfile.1 ] и файл журнала переименован в файл журнала.0 .

Решение о вращении может быть основано на счетчике, который хранится в самом скрипте. Когда он достигает 1000, он сбрасывается до нуля.

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

Или вы можете получить размер, например, с помощью wc -c logfile , и выполнить ротацию на основе превышения определенного размера.Таким образом, файл никогда не нужно сканировать для определения состояния.

0
27.01.2020, 19:44

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

мой код выглядит примерно так:

TMP_FILE="$(mktemp "${TMPFILENAME}.XXX")"

for FILE in "${LOGFILE_DIR}"/* ; do
    tail -n $MAXLINES "${FILE}" > "${TMP_FILE}"
    if [ $(ls -g "${TMP_FILE}" | awk '{print $4}') -lt $(ls -g "${FILE}" | awk '{print $4}') ] ; then
        cp "${TMP_FILE}" "${FILE}"
    fi
done   

Итак, если файлы находятся в одной и той же файловой системе, вы также можете предоставить пользователям разные права, а в ${LOGFILE_DIR} вы изменяете длину, например Я делаю.

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

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

logrotate может быть лучше. Но я доволен этим решением.

Не беспокойтесь о «», но в моем случае есть несколько файлов с пробелами и другими специальными буквами, и если я не использую «» или {}, все работает плохо. .

Например, существует каталог, в котором старые файлы автоматически заархивируются в OLDFILE.zip, и все, что заархивировано, также указано в файле .zip_log, поэтому .zip_log также находится в этом каталоге, но в LOGFILE_DIR у меня есть:

ln .zip_log "${LOGFILE_DIR}/USER_ZIP_log"

аналогичный файл, так как это жесткая ссылка.

0
27.01.2020, 19:44

Если другой процесс обновляет файл журнала и вы хотите избежать вмешательства в него, лучше всего сохранить второй файл. Второй файл (, назовем его "архивным файлом" ), будет содержать последние nзаписанные строки.

Чтобы сделать это максимально аккуратно, сначала переместите существующий файл журнала во временное расположение. Затем объедините его с ранее сохраненным архивным файлом и сохраните до nстрок.

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

#!/bin/bash

log_dir=/path/to/my/logs
log_filename=my_file.log
lines_to_keep=1000
archive_filename="${log_filename}.001"

work_dir="$(mktemp -d -p "$logdir")" && \
    touch "$log_dir/$archive_filename" && \
    touch "$log_dir/$log_filename" && \
    mv "$log_dir/$archive_filename" "$work_dir/" && \
    mv "$log_dir/$log_filename" "$work_dir/" && \
    cat "$work_dir/$archive_filename" "$work_dir/$log_filename" | \
        tail -n $lines_to_keep > "$log_dir/$archive_filename" && \
    rm "$work_dir/$archive_filename" && \
    rm "$work_dir/$log_filename" && \
    rmdir "$work_dir"
0
17.02.2020, 23:18

Теги

Похожие вопросы