среда, 17 апреля 2019 г.

Предупреждение о заполненности диска через bash

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

Несмотря на имевшийся ранее опыт эксплуатации жёстких дисков с заполненностью до 99 % , такие диски являлись хранилищами данных, операции записи и удаления на которых производились не ежедневно. На диске с установленной системой такое состояние вряд ли можно считать приемлемым.

Стимулами к автоматизации уведомления о сильной заполненности диска явились сравнительно малая ёмкость винчестера и оказание содействия другу, совершенно недавно переметнувшемуся из союза пользователей Windows в сообщество Linux, имеющему точно такой же винчестер как и у меня объёмом в 500 Гигабайт (при форматировании в основной раздел с файловой системой его объём превращается в 465 Гигабайт).


Так как считается, что заполнять диск данными более чем 90 % не является желательным, а для операций по исправлению ошибок на файловой системе (особенно в ходе которых будут осуществляться попытки перезаписи данных из плохих кластеров в хорошие) может потребоваться не менее 5 % доступного для записи места на диске, то было принято решение автоматически уведомлять о наличии свободного места (доступного пользователю), начиная от его значений в 10 % и ниже. Несмотря также на то, что по сравнению с ntfs файловая система ext4 в значительно меньшей степени подвержена фрагментации, её чрезмерное заполнение может дурно повлиять на производительность. Если кому интересно про дефрагментацию в Linux, то читать здесь.

В публикации рассматривается диск, на котором имеется 1 раздел с установленной системой Linux. Отдельного раздела под /home не создавалось, домашний каталог расположен в корне файловой системы, поэтому в дальнейшем имеется в виду, что диск соответствует /dev/sda1

Автоматизация уведомления достигается запуском скрипта при старте системы или через назначение пользовательского задания cron.

Формируемые в процессе работы скрипта данные записываются в выделенный для этой цели каталог  /home/user/scripts/temp , который в скрипте будет выступать как переменная dest. Создаваемые файлы имеют имена df*.txt, где под символом * понимаются значения от 1 до 6. Под user понимается домашний каталог пользователя, под логином которого осуществлён вход в систему.

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

#!/bin/bash
dest=/home/user/scripts/temp

Получить сведения о дисковом пространстве:

df -h /dev/sda1 > $dest/df1.txt

Файл df1.txt будет иметь примерно такой вывод:


Внимательный пользователь может задаться вопросом о разнице между снимком экрана в GParted (в начале заметки) и только что приведенным. Дело в том, что используются разные алгоритмы подсчёта, при которых какие-то данные учитываются, а какие-то – нет. Кроме того, ряд данных может оказаться недоступным для чтения. 
Определённую информацию о существующих в этом вопросе разночтениях можно получить здесь и здесь. Лично мне понравится комментарий: "Другое дело нужно не забывать о разнице между K/M/G и KiB/MiB/GiB. Собственно за *iB хочется вырвать все конечности маркетологам производителей HDD, которые внедрили K=1000 в информационных системах когда изначально K было 1024 для IT и 1000 для физиков.".
Кроме того, вывод df1.txt отображает более объективную информацию, так как показывает дисковое пространство, которое доступно (см. Дост 44G). "Доступно" – это именно тот объём диска, на который пользователь может осуществить запись данных под своими полномочиями в системе. Часть свободного дискового пространства диска пользователю не доступна для записи.

Из файла df1.txt необходимо получить вывод 5-го столбца и записать его в файл df2.txt

cat $dest/df1.txt | awk '{print($5)}' > $dest/df2.txt


Из полученного результата для дальнейшего использования нужны только цифры, поэтому из df2.txt последовательно удаляются слово Использовано% и символ % . Результаты операций записываются в файлы df3.txt и df4.txt

str=Использовано%
while read LINE; do
echo "${LINE##*$str}"
done < $dest/df2.txt | tee $dest/df3.txt


rev $dest/df3.txt | cut -c 2- | rev > $dest/df4.txt


Так как далее скрипт будет "читать" вывод из файла, то в df4.txt необходимо избавиться от первой строки, которая является пустой. Результат записывается в файл df5.txt

sed -n 2p $dest/df4.txt > $dest/df5.txt


Предупреждение о заполненности диска использует условие "если значение равно x, то y (выводится предупреждение), а если не равно х, то z (ничего не делать).

Выполнение условия реализуется инструкцией:

if [ "значение" -eq x ];
then
вывод предупреждения
else
:
fi

Но параметр -eq не применяется с двузначными числами, поэтому из df5.txt необходимо удалить первый символ и записать результат в df6.txt

rev $dest/df5.txt | cut -c 1 | rev > $dest/df6.txt


Полученный результат уже можно использовать в операциях соответствия заданным условиям.

Предусматривается, что при значениях df6.txt от 0 до 9 будут выводиться предупреждения:

0 – осталось свободно 10 % диска
1 – осталось свободно 9 % диска
2 – осталось свободно 8 % диска
3 – осталось свободно 7 % диска
4 – осталось свободно 6 % диска
5 – осталось свободно 5 % диска
6 – осталось свободно 4 % диска
7 – осталось свободно 3 % диска
8 – осталось свободно 2 % диска
9 – осталось свободно 1 % диска

которые будут отображаться на экране до тех пор, пока пользователь не нажмёт кнопку OK. Содержанию файла df6.txt присваивается переменная value.

value=`cat $dest/df6.txt`
if [ $value -eq 0...9 ];
then
zenity --width=190 --height=50 --info --text "\nОсталось свободно 10...1 % диска." 2>/dev/null
else
:
fi

Теоретически, при каждом запуске скрипта в имеющиеся в файлах df*.txt значения будут записываться новыми. Но эти промежуточные данные можно и удалять. Например, удалить перечисленное:

rm $dest/df1.txt $dest/df2.txt $dest/df3.txt $dest/df4.txt $dest/df5.txt $dest/df6.txt

или найти и удалить объекты, совпадающие по шаблону имени – 

find $dest -name df*.txt -delete

Всё было бы неплохо, если бы полученные в df5.txt значения были от 90 и выше. Но они могут быть и 20, и 30, и 70 ... В таком случае если занято 72% диска, то будет выдано предупреждение о наличии только 8% доступного (свободного) места на диске, что далеко не соответствует действительности. Поэтому после получения значения df5.txt производится дополнительное сравнение: если 89 и менее, то всё хорошо и ничего делать не надо, в противном случае необходимо выдавать предупреждения.

Проверка реализуется следующим образом. Читается значение a, которое и является результатом вывода df5.txt  Значению b устанавливается пороговая величина 89. Затем производится сравнение двузначных чисел a и b.

a=`cat $dest/df5.txt`
b=89
if [ $a -le $b ]
then
# 89% и меньше, ничего делать не надо, всё в порядке
else
# команды вывода предупреждения
fi

Команды вывода предупреждений оформляются в отдельный скрипт alarm.sh, который будет запущен в случае else (см. выше).

В конечном итоге получилось 2 скрипта: diskusage.sh и alarm.sh

Листинг diskusage.sh:

#!/bin/bash
dest=/home/user/scripts/temp
df -h /dev/sda1 > $dest/df1.txt
cat $dest/df1.txt | awk '{print($5)}' > $dest/df2.txt
str=Использовано%
while read LINE; do
echo "${LINE##*$str}"
done < $dest/df2.txt | tee $dest/df3.txt
rev $dest/df3.txt | cut -c 2- | rev > $dest/df4.txt
sed -n 2p $dest/df4.txt > $dest/df5.txt
a=`cat $dest/df5.txt`
b=89
if [ $a -le $b ]
then
:
else
/home/user/scripts/alarm.sh
fi
#   Если необходимо удалить все полученные df*.txt
#,  то убрать символ решётки (#) в строке ниже
#find $dest -name df*.txt -delete
exit

Листинг alarm.sh:

#!/bin/bash
level=/home/user/scripts/temp
rev $level/df5.txt | cut -c 1 | rev > $level/df6.txt
value=`cat $dest/df6.txt`
if [ $value -eq 0 ];
then
zenity --width=190 --height=50 --info --text "\nОсталось свободно 10 % диска." 2>/dev/null
else
:
fi
if [ $value -eq 1 ];
then
zenity --width=190 --height=50 --info --text "\nОсталось свободно 9 % диска." 2>/dev/null
else
:
fi
if [ $value -eq 2 ];
then
zenity --width=190 --height=50 --info --text "\nОсталось свободно 8 % диска." 2>/dev/null
else
:
fi
if [ $value -eq 3 ];
then
zenity --width=190 --height=50 --info --text "\nОсталось свободно 7 % диска." 2>/dev/null
else
:
fi
if [ $value -eq 4 ];
then
zenity --width=190 --height=50 --info --text "\nОсталось свободно 6 % диска." 2>/dev/null
else
:
fi
if [ $value -eq 5 ];
then
zenity --width=190 --height=50 --info --text "\nОсталось свободно 5 % диска." 2>/dev/null
else
:
fi
if [ $value -eq 6 ];
then
zenity --width=190 --height=50 --info --text "\nОсталось свободно 4 % диска." 2>/dev/null
else
:
fi
if [ $value -eq 7 ];
then
zenity --width=190 --height=50 --info --text "\nОсталось свободно 3 % диска." 2>/dev/null
else
:
fi
if [ $value -eq 8 ];
then
zenity --width=190 --height=50 --info --text "\nОсталось свободно 2 % диска." 2>/dev/null
else
:
fi
if [ $value -eq 9 ];
then
zenity --width=190 --height=50 --info --text "\nОсталось свободно 1 % диска." 2>/dev/null
else
:
fi
exit

То есть, проверочным запускаемым скриптом является diskusage.sh  Если значение a (полученное из файла df5.txt) составит 90 и более, то запускается скрипт alarm.sh

Для приведенных в примере данных файлов df*.txt результат работы скриптов приводится ниже:


Комментариев нет:

Отправить комментарий