LINUX.ORG.RU
ФорумAdmin

Скрипт удаления старых файлов при переполнении диска.

 , ,


0

2

Здравствуйте, коллеги.

Имею в хозяйстве систему видеонаблюдения: сервер (обычный ПК), несколько ip видеокамер Acti, Axis, PoE инжекторы к камерам, гигабитный хаб.

Сервер представляет из себя обычный ПК с двумя сетевыми картами, 2 жестких диска (320GB системный, 2000GB под архив с фотографиями ), операционная система Linux Centos 6 x64, помимо базовой системы установлены пакеты: motion, samba, ntp, nload, htop, mc .

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

Данное решение было выбрано потому что нужна была максимальная глубина архива. В зависимости от места установки камеры получается 1.5 — 3ГБ ( до 10000 фотографий) в день на одну камеру. Разрешение фотографии 1280*800 , размер около 125КБ. Также хочу заметить что motion вообще не грузит процессор, к серверу подключено в данный момент 5 камер, загрузка сети 25 Мбит/с, загрузка процессора 5% (Intel(R) Core(TM) i3 CPU 550 @ 3.20GHz), load average 0.06 0.13 0.19 .

Полный путь до файла сейчас выглядит так /mnt/2000gb/photo/camera05/2014/12/03/2014_12_03_00_14_51-01.jpg .

Удалять старые файлы нужно было только при заполнении диска, например до 90%. Для этого я написал следующий скрипт. Скрипт был запихнут в cron выполнятся раз в час.

#!/bin/sh

#Скрипт удаления старых файлов при переполнении диска
# $1 - доспустимый размер занятого места в процентах, например 90, без знака процентов %    
# $2 - точка монтирования, например /mnt/2000gb 
# $3 - имя каталога для очистки старых файлов, например /mnt/2000gb/photo
# запускать так sh remove-old.sh 90 /mnt/2000gb /mnt/2000gb/photo

if [ "$#" -eq 3 ]
   then

#Определяем переменные из аргуметов переданных скрипту
NOT_MORE_PERCENT=$1
MOUNT_POINT=$2
TARGET_DIRECTORY=$3

#Определяем процент занятого места на диске по точке монтирования этого диска
REAL_PERCENT=$(df -h | grep $MOUNT_POINT | awk '{print $5}' | sed 's/.$//')

#В случае если реальный процент больше или равен заданному значению удаляем лишние файлы
if [ "$REAL_PERCENT" -ge "$NOT_MORE_PERCENT" ]
 then

#Определяем дату самого старого файла путем обратной сортировки по имени 
cd $TARGET_DIRECTORY
MOST_OLD_DATE=$(ls -1ARrl --time-style=long-iso | tail -n1 | awk '{print $6}')

#Определяем даты +день и -день от самой старой даты, нужно для корректного задания временнного диапазона команды find
DAY_BEFORE_MOST_OLD_DATE=$(date -d "$MOST_OLD_DATE -1 days" "+%Y-%m-%d")
DAY_AFTER_MOST_OLD_DATE=$(date -d "$MOST_OLD_DATE +1 days" "+%Y-%m-%d")

#Находим все файлы заданной даты в нашем каталоге и удаляем, удаляются только файлы!!!
find $TARGET_DIRECTORY -type f -newermt "$DAY_BEFORE_MOST_OLD_DATE 23:59:59" -not -newermt "$DAY_AFTER_MOST_OLD_DATE" -delete

#Находим все пустые директории в заданной директории и удаляем
find $TARGET_DIRECTORY -type d -empty -delete

  else
#В случае если реальный процент меньше заданного значения ничего не делаем
  echo "Еще есть немножко свободного места"
  exit 0
fi

 else
echo "Количество аргументов должно быть равно 3-м"
echo "Введенное количество аргуметов $#"
exit 1
fi

И он работал если файлов было не более 50GB. Сейчас он выполняется настолько долго что ничего не происходит. Виснет на выполнении команды

#Определяем дату самого старого файла путем обратной сортировки по имени 
ls -1ARrl --time-style=long-iso | tail -n1 | awk '{print $6}'
Собственно вопрос: как при переполнении(например более 90%) диска удалить директории с фотографиями только за один самый старый день?


В чём смысл этого «странного» подхода: использовать mtime файла, последнего в сортировке по имени? У вас же всё исходно разложено по отдельным каталогам — каждый день в отдельный каталог. Вот и сортируйте каталоги с помощью ″sort″ (с опцяими -t -k). А если у вас там в каталогах бардак и имя файла это не дата его создания, то ваш подход ничем не лучше.

P.S. И поменяйте первый ″if″, что при ″$#″ не 3 был выход, чтобы не было такого большого блока кода после ″if″.

mky ★★★★★
()

Собственно вопрос: как при переполнении(например более 90%)

man df

удалить директории с фотографиями только за один самый старый день?

1. найти последнюю фотку, вывести её дату в формате YYYYMMDD

2. удалить все фотки начиная YYYYMM(DD-1)

3. повторить пп1,2 для всех директорий.

if [ «$REAL_PERCENT» -ge «$NOT_MORE_PERCENT» ]

if (( REAL_PERCENT >= NOT_MORE_P ))

ls -1ARrl --time-style=long-iso | tail -n1 | awk '{print $6}'

find -printf "%TY%Tm%Td %p\n"

emulek
()

zsh

ls -1ARrl --time-style=long-iso | tail -n1 | awk '{print $6}'

Сахарок для определения старейшего файла

ls -l **/*(Om[1]) 
Но проще конечно просто удалять старейшую директорию
rm -rf *(/Om[1])

zolden ★★★★★
()
Ответ на: комментарий от mky

"Странная" сортировка

mky, Такой подход к сортировке был выбран не случайно. опция -t отрабатывает не корректно. Вот так отрабатывает моя сортировка

[root@server-cam-arp photo]# ls -1ARrl --time-style=long-iso | tail -n1
-rw-r--r-- 1 root root 115793 2013-01-23 09:22 2013_01_23_09_22_01-01.jpg
И я знаю что действительно самый старый файл 2013-01-23 . А вот стоит заменить -r на -t . Отрабатывает не корректно. И также не корректно отрабатывало когда было мало файлов меньше 10Гб.
[root@server-cam-arp photo]# ls -1ARtl --time-style=long-iso | tail -n1
-rw-r--r-- 1 root root 134672 2014-04-21 11:24 2014_04_21_11_24_52-00.jpg
Поэтому файлы создаются с именем файла по которому можно сортировать по времени.

lext55
() автор топика
Ответ на: "Странная" сортировка от lext55

А почему при замене ″-r″ на ″-t″ вывод ″ls″ пропускается через ″tail″, а не через ″head″?

Мне ваша подход к сортировки не нравится тем, что если случайно у файла mtime окажется текущим, то ваш скрипт грохнет фото за текущий день. Причём совсем не обязательно редактировать старое фото, можно случайно сделать ″touch -m″ на него, или скопировать фото, или просто опечататься в скрипте и вместо перенаправления stderr создать файл с именем ″2″.

И я не знаю, зачем вам вобще искать по имени файла, если у вас есть имена каталогов:

find . -type d | sort -n  -t '/' -k3,5 | head -n 1

и на получаемый результат (имя каталога) ″rm -rf″.

Между ″find″ и ″sort″ ещё не помешает ″grep '^\./camera[0-9][0-9]/20[0-9][0-9]/[012][0-9]/[0123][0-9]$″, чтобы лишних каталогов не нашлось.

BTW, если ″df″ указывать имя каталога, она сама находит точку монтрирования. Поэтому наличие второго параметра у скрипта скорее вред, чем польза — если случайно указать другой раздел.

mky ★★★★★
()
Ответ на: комментарий от mky

А почему при замене ″-r″ на ″-t″ вывод ″ls″ пропускается через ″tail″, а не через ″head″?

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

[root@server-cam-arp 2000gb]# ls -1ARtl --time-style=long-iso | head -n10
.:
итого 20
drwxr-xr-x 7 root root  4096 2014-11-28 10:50 photo
drwx------ 2 root root 16384 2013-01-10 11:17 lost+found

./photo:
итого 20
drwxr-xr-x 4 root root 4096 2015-01-01 06:24 camera04
drwxr-xr-x 5 root root 4096 2015-01-01 06:18 camera01
drwxr-xr-x 4 root root 4096 2015-01-01 03:05 camera03
Самое интересное что выдаются не самые свежие версии файлов. Билеберда. Такое ощущение что используется опция -u (Использовать при сортировке время последнего доступа к файлу вместо времени последней модификации файла. ), хотя я ее не указывал.

lext55
() автор топика
Ответ на: комментарий от anonymous

а не проще удалять файлы которые старше определенного времени?

Нет не проще. по ТЗ (как захотелось генеральному) нужно хранить до тех пор пока есть свободное место. да можно рассчитать что одна камера дает примерно 3 Гб фотографий в сутки. умножить на количество камер, поделить свободное место на имеющееся число гигабайт в день. Получим количество дней. НО количество камер не постоянно. Сегодня захотели сюда камеру. Завтра туда. После завтра снять оттуда, т.к. она там больше не нужна. А хранить фотки нужно максимально долго. Поэтому только такое решение.

lext55
() автор топика
Ответ на: комментарий от mky

Готовый скрипт

  • Решил полностью отказаться от сортировки по полям mtime, ctime, atime. Ибо не работает как надо. Либо руки у меня кривые.
  • Т.к. время создания файла находится строго в начале файла, имеет строго определенный формат ГГГГ_ММ_ДД, будем искать файлы начинающиеся с нужной нам даты.
  • Собственно сам скрипт
    #!/bin/sh
    
    #Скрипт удаления старых файлов при переполнении диска
    # $1 - доспустимый размер занятого места в процентах, например 90, без знака процентов %    
    # $2 - точка монтирования, например /mnt/2000gb 
    # $3 - имя каталога для очистки старых файлов, например /mnt/2000gb/photo
    # запускать так sh remove-old.sh 85 /mnt/2000gb /mnt/2000gb/photo
    
    if [ "$#" -eq 3 ]
       then
    
    #Определяем переменные из аргуметов переданных скрипту
    NOT_MORE_PERCENT=$1
    MOUNT_POINT=$2
    TARGET_DIRECTORY=$3
    
    #Определяем процент занятого места на диске по точке монтирования этого диска
    REAL_PERCENT=$(df -h | grep $MOUNT_POINT | awk '{print $5}' | sed 's/.$//')
    
    #В случае если реальный процент больше или равен заданному значению удаляем лишние файлы
    if [ "$REAL_PERCENT" -ge "$NOT_MORE_PERCENT" ]
     then
    
    # Т.к. все файлы начинаются с ГГГГ_ММ_ДД сортируем обратной сортировкой, выбираем последнюю строчку, 
    # выбираем имя файла, отрезаем от имени первых 10 знаков.
    cd $TARGET_DIRECTORY
    MOST_OLD_DATE=$(ls -1ARrl | tail -n1 | awk '{print $9}' | cut -c1-10 )
    
    #Находим все файлы по имени в нашем каталоге и удаляем, удаляются только файлы!!!
    find $TARGET_DIRECTORY -type f -name "$MOST_OLD_DATE*" -delete
    
    #Находим все пустые директории в заданной директории и удаляем
    find $TARGET_DIRECTORY -type d -empty -delete
    
      else
    #В случае если реальный процент меньше заданного значения ничего не делаем
      echo "Еще есть немножко свободного места"
      exit 0
    fi
    
     else
    echo "Количество аргументов должно быть равно 3-м"
    echo "Введенное количество аргуметов $#"
    exit 1
    fi
    
  • Время выполнения скрипта. Жесткий диск 2000gb seagate baccracuda, файловая система ext4, 1.5TB фотографии размером 125КБ каждая, скрипт выполняется от 10 до 25 минут, ну если превысило допустимый процент свободного места.
lext55
() автор топика
Ответ на: Готовый скрипт от lext55

Можно попробовать использовать -v если есть проблемы с сортировкой или записывать имя последнего удаленного файла и искать по регулярке

anonymous
()

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

pavel38
()
Последнее исправление: pavel38 (всего исправлений: 1)

Задача стояла аналогичная, только архив был 4 Тб

pavel38
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.