Хорошо, обо всем по порядку:
Да, мне известен инструмент logrotate, который обычно используется для чего-то вроде этого. Однако, поскольку файл журнала, который я хочу повернуть, уже содержит отметку времени в имени файла, logrotate никогда не удалит старые журналы.
Этот сценарий должен:
- скажите приложению создать новый файл журнала (через SIGHUP)
- найти все существующие необработанные файлы журналов приложения
- сжать все файлы журнала, кроме того, который в настоящее время используется приложением
- сохранить 7 последних журналов и удалить остальные.
Насколько я могу судить, все вроде работает нормально, но мне любопытно, можно ли что-нибудь улучшить.
#!/usr/bin/bash
procname="foo"
srcpath="/var/log"
srcname="*${procname}.log" # example: 2021-02-05_1200_foo.log
count=7
echo "rotate $procname logs: ${srcpath}/${srcname} ($count rotations)"
pid="$(pidof $procname)"
if [[ ! $? == 0 ]]
then
# don't rotate anything if the application is not running
echo "$procname process not running"
exit 1
fi
# ask the application to create a new logfile
kill -HUP "$pid"
sleep 1 #probably not necessary?
# get array of all logfiles (should be exactly 2 in most cases)
mapfile -t list < <(find "$srcpath" -maxdepth 1 -name "$srcname" | sort)
size=${#list[@]}
# don't do anything unless there are at least 2 files
if [[ $size -lt 2 ]]
then
echo "nothing to do"
exit 0
fi
# find the active logfile (should be the last one) and delete it from the array
for ((i=size-1; i>=0; i--));
do
if [[ $(find -L /proc/"$pid"/fd -inum "$(stat -c '%i' "${list[i]}")") ]]
then
unset "list[i]"
break
fi
done
# compress all remaining files (usually just one)
gzip "${list[@]}"
unset list
unset size
# get array of all compressed logfiles
mapfile -t list < <(find "$srcpath" -maxdepth 1 -name "$srcname.gz" | sort)
size=${#list[@]}
if [[ $size -gt $count ]]
then
idx=("${!list[@]}")
# remove $count most recent files from $list
for i in "${idx[@]: -$count:$count}"
do
unset "list[$i]"
done
# delete the remaining old files
rm -f "${list[@]}"
fi
exit 0
1 ответ
Shellcheck указывает на это:
pid="$(pidof $procname)" if [[ ! $? == 0 ]] then
Мы можем написать это более четко
if ! pid="$(pidof $procname)"
then
Вскоре после этого:
# don't rotate anything if the application is not running echo "$procname process not running"
Это похоже на сообщение об ошибке — перенаправьте это на &2
.
Я немного обеспокоен
# find the active logfile (should be the last one) and delete it from the array
Если демон не успел открыть новый файл к тому времени, как мы дойдем до этого места, то синхронизация будет нарушена. Тем не менее, это, вероятно, не имеет значения — у нас будет еще один невращенный файл до следующего запуска, что не вызывает большого беспокойства.
Будьте осторожны с такими командами:
gzip "${list[@]}"
Это хорошая идея использовать --
поэтому мы можем быть уверены, что имена файлов, начинающиеся с -
не интерпретируются как варианты.
Также такие команды, как gzip
может потерпеть неудачу — действительно ли мы хотим продолжать, если они это сделают? (На этот вопрос не так просто ответить, поскольку одна из вероятных причин — «нет места на устройстве», и в этом случае мы действительно хотим удалить некоторые файлы!)
Спасибо! Я не знал, что у вас может быть назначение внутри предложения if, это намного лучше, чем
$?
версия. Что касается проблемы рассинхронизации, поэтому я добавилsleep 1
, что, конечно, тоже не является гарантией, но, надеюсь, лучше, чем ничего. Не думал о--
, я добавлю это вgzip
иrm
на всякий случай (даже если имена файлов не должны начинаться с-
). Мне нужно подумать об обработке ошибок … честно говоря, я не совсем уверен, что я хочу делать, если gzip не работает— Феликс Джи
Да, я видел сон с его комментарием, поэтому знал, что вы о нем знаете. Извините, я не могу предложить ничего лучше.
— Тоби Спейт
я мысль списки аргументов не начинались бы с
-
, но часто проще просто уронить--
в команду, чтобы спасти драгоценный ум, рассуждая об этом!— Тоби Спейт