Обновление скрипта резервного копирования

Обновил скрипт для резервного копирования. Убрал вызов bc, вынес всё в отдельные функции, причесал код, чтобы ShellCheck был счастлив:

#!/usr/local/bin/bash
 
BACKUP_ROOT=/var/backups/manual/
BACKUP_DIR="$BACKUP_ROOT"$(date +"%Y-%m-%d/%H-%M")
PREFIX=$(date +"%Y%m%d_%H%M")
LIMIT=$((4*1024*1024))
 
exit_on_error() {
    exit_code=$?
    if [ $exit_code -ne 0 ]; then
        >&2 echo -e "FAIL"
        exit $exit_code
    fi
}
 
print_used_space() {
    printf "Used space: "
    SIZE=$(du -sB 1 $BACKUP_ROOT | cut -f 1)
    printf "%sMb(%s%%)\n" "$((SIZE / 1024))" "$((SIZE * 100 / LIMIT))"
}
 
backup_etc() {
    FILENAME="$PREFIX"_etc.tar.bz2
    printf "Creating %s .. " "$FILENAME"
    if /usr/bin/tar -Pjcf "$BACKUP_DIR"/"$FILENAME" /etc /usr/local/etc /home /var/db/ports /var/named/etc/namedb /root/scripts > /dev/null 2>&1; then
        printf "OK\n"
    else
        exit_on_error
    fi
}
 
backup_site() {
    FILENAME="$PREFIX"_www.tar.bz2
    printf "Creating %s .. " "$FILENAME"
    if /usr/bin/tar -Pjcf "$BACKUP_DIR"/"$FILENAME" /usr/local/www > /dev/null; then
        printf "OK\n"
    else
        exit_on_error
    fi
}
 
backup_db() {
    FILENAME="$PREFIX"_db.sql.bz2
    printf "Creating %s .. " "$FILENAME"
    if /usr/local/bin/mysqldump --login-path=backup --opt --all-databases --triggers --routines --events | bzip2 -c > "$BACKUP_DIR"/"$FILENAME"; then
        printf "OK\n"
    else
        exit_on_error
    fi
}
 
remove_old_files() {
    removed=0
    for days in $(seq 100 -1 0)
    do
        SIZE=$(du -sB 1 $BACKUP_ROOT | cut -f 1)
        if [[ $SIZE -le $LIMIT ]]; then
            break
        fi
        if [[ -z "$(find $BACKUP_ROOT -type f -mtime +"$days")" ]]; then
            continue
        fi
        printf "Removing files older than %d days:\n" "$days"
        find $BACKUP_ROOT -type f -mtime +"$days"d -delete -print
        find $BACKUP_ROOT -empty -type d -delete -print
        removed=1
    done
 
    if [ $removed -ne 0 ]; then
        true
        return
    fi
 
    false
}
 
if [ ! -d "$BACKUP_DIR" ]; then
        mkdir -p "$BACKUP_DIR"
fi
 
backup_etc
backup_site
backup_db
print_used_space
remove_old_files && print_used_space
true
Краткая инструкция по обновлению порта для сопровождающих

Примерно с 2008 года совершенно случайно являюсь сопровождающим порта sysutils/archivemount в ОС FreeBSD и недавно стал получать сообщения от их багтрекера. Их Bugzilla с упорством достойным поощрения настойчиво раз в неделю присылала мне письма об ошибках. Так что ничего не оставалось делать, как обновить соответствующий порт и в результате родилась эта инструкция.

# Делаем копию оригинала
cp -r /usr/ports/sysutils/archivemount/ /usr/ports/sysutils/archivemount.bak
# Обновляем Makefile (PORTVERSION=new_version, PORTREVISION=0)
vim /usr/ports/sysutils/archivemount/Makefile
# Обновляем файл distinfo командой make makesum
cd /usr/ports/sysutils/archivemount && make makesum
# Генерируем diff (рекомендуется использовать git diff)
diff -ruN /usr/ports/sysutils/archivemount.bak /usr/ports/sysutils/archivemount > archivemount.diff

Заливаем этот diff через форму багтрекера с припиской в начале [maintainer update]. В качестве примера можно посмотреть обновление archivemount. Также приложите CHANGELOG со списком изменений и, разумеется, проверьте работу порта и новой версии приложения перед отправкой.
Что ещё почитать:
* FreeBSD Porters Handbook
* Руководство FreeBSD по созданию портов

Скрипт для резервного копирования

Всем привет, обновил скрипт для резервного копирования с учётом того, что я вообще-то программист, а не просто айтишник! Он стал более интеллектуально определять и удалять старые файлы, учитывать ограничение в 4.5Gb (на FTP для бекапа доступно 5Gb) и успешность операций, добавлены сообщения об ошибках. И бонусом сообщения раскрашены в разные цвета, нейтральные выделены жирным, хорошие зелёным, а плохие красным цветом — красота! Скрипт проверен на сайте ShellCheck, который я настоятельно рекомендую к использованию. Если найдёте ошибку или вам есть что добавить, смело пишите комментарий.

#!/usr/local/bin/bash
 
# Основная папка для архивов
BACKUP_ROOT=/var/backups/manual/
# Папка, куда непоредственно пишем файлы, выглядит как BACKUP_ROOT/ГОД/МЕСЯЦ/ДЕНЬ
BACKUP_DIR="$BACKUP_ROOT"$(date +"%Y/%m/%d")
# Время запуска скрипта. Все файлы имеют вид имя_файла_%ЧАС%%МИНУТА%.tag.bz2
TIME=$(date +"%H%M")
# Ограничение хранилища в килобайтах для проверки
LIMIT=$(echo "4096*2^10"|bc)
# Ограничение хранилища в мегабайтах для вывода в сообщениях
HLIMIT=$(echo "$LIMIT/1024"|bc)"Mb"
 
# Функция выход в случае ошибки
exit_on_error() {
    # Получаем код ошибки
    exit_code=$?
    # Входное сообщение
    message=$1
    if [ $exit_code -ne 0 ]; then
        # Выводим сообщение в stderr
        >&2 echo -e "\e[31m${message}\e[0m"
        # Выходим к кодом exit_code
        exit $exit_code
    fi
}
 
# Если папки нет
if [ ! -d "$BACKUP_DIR" ]; then
    # Создаём папку со всеми промежуточными подпапками
    mkdir -p "$BACKUP_DIR"
fi
 
printf "\e[1mSearching space for backup\e[0m .. "
# Цикл от 100 дней до нуля
for days in $(seq 100 -1 0)
do
    SIZE=$(du -sB 1 $BACKUP_ROOT | cut -f 1)
    HSZ=$(echo "$SIZE/1024"|bc)"Mb"
    # Если размер хранилища не превышает лимита
    if [[ $SIZE -le $LIMIT ]]; then
        # Выводим сообщение и прерываем цикл
        printf "[%s/%s] .. " "$HSZ" "$HLIMIT"
        break
    fi
    # Если нет ни одного файла старше $days дней
    if [[ -z "$(find $BACKUP_ROOT -type f -mtime +"$days")" ]]; then
        # Продолжаем цикл
        continue
    fi
    printf "\e[31m%s/%s]\e[0m .. " "$HSZ" "$HLIMIT"
    # Удаление файлов старше $days прошло успешно
    if find $BACKUP_ROOT -type f -mtime +"$days"d -delete > /dev/null; then
        # Выводим сообщение 
        printf "CLEAN (older than %s days) .. " "$days"
    else
        # Выходим с сообщением FAIL
        exit_on_error "FAIL"
    fi
    # Удаляем пустые папки, чтоб не мусорить
    find $BACKUP_ROOT -empty -type d -delete
done
echo -e "\e[32mOK\e[0m"
 
printf "\e[1mBackuping etc files\e[0m .. "
/usr/bin/tar -Pjcf "$BACKUP_DIR"/etc_"$TIME".tar.bz2 /etc /usr/local/etc /home /var/db/ports /var/named/etc/namedb /root/scripts > /dev/null 2>&1 && echo -e "\e[32mOK\e[0m" || exit_on_error "FAIL"
 
printf "\e[1mBackuping www folder\e[0m .. "
/usr/bin/tar -Pjcf "$BACKUP_DIR"/www_"$TIME".tar.bz2 /usr/local/www > /dev/null && echo -e "\e[32mOK\e[0m" || exit_on_error "FAIL"
 
printf "\e[1mBackuping SQL databases\e[0m .. "
/usr/local/bin/mysqldump --login-path=backup --opt --all-databases --triggers --routines --events | bzip2 -c > "$BACKUP_DIR"/sql_"$TIME".sql.bz2 && echo -e "\e[32mOK\e[0m" || exit_on_error "FAIL"

Откровенно говоря, не до конца понимаю, в каких единицах считает занятое место команда du. Предполагаю, что в килобайтах.

P.S. Для того, чтобы получить вывод без цвета, использую утилиту textproc/ansifilter:

script.sh | ansifilter --text
Добавил меню

Всем привет! Вам конечно всё равно, но я добавил меню. Теперь у меня есть навигация не только по меткам, но и по рубрикам. Можно посмотреть все Путешествия или рубрику Программирование включая подрубрики C++, Python, Java и так далее. Всё добавлено вручную, никакой автоматизации.

Поддержка меню в WordPress встроена изначально, все пункты и подменю добавляются в админке, но поскольку тема у меня самописная, пришлось попотеть с CSS и немного с JavaScript. Что-то натырено со сторонних сайтов, что-то взято из видео ниже.

Добавить меню хотел очень давно, но не хватало стимула и знаний. Спасибо каналу хлопца Евгения. После просмотра его видео про адаптивное меню решил сменить профессию сделать похожее на своём сайте.

Дайте знать, если плашка с рубрикой нужна к каждой статье. Хотя кого я спрашиваю, ходит на сайт два с половиной человека. Один из них гуглбот, а второй — это я.

UPD: В мобильной версии сайта добавил меню с помощью плагина WP Mobile Menu.

Где размять мозги программисту? Тренировочный полигон для айтишников

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

А программистам и похвастаться нечем. Они не бегают и стрелять не умеют, а сидят сгорбленные, уставившись красными глазами в монитор и что-то пишут. Чем он занят? Зачем он здесь? Никто не знает.

А работодатель хочет знать как определить сильного программиста. По хиленьким ручкам, красным глазкам, горбатой спине или катышкам на свитере? Ну, допустим, текущему работодателю определить просто — надо брать того, кто не слишком сильно пахнет, а как быть с новым работодателем?

Вот пришёл ты такой красивый на собес и тебе прямо с порога — давай сортировку пузырьком пиши в уме! А ты работаешь в своём НИИ уже пятый десяток и всегда использовал метод sort() из вашей секретной сверхбыстрой библиотеки на Фортране и знать не знаешь что у неё внутри. И библиотека та написана учёным седовласым мужем, чьё имя с отчеством произносятся в конторе с придыханием и пиететом и бюст евоный стоит сразу при входе в холле. И значит это ровно то, что часть мозга, которая отвечает за простейшие алгоритмы атрофировалась за ненадобностью. Потому что все эти вещи пишутся один раз и навсегда, а не каждый день, как полагает потенциальный работодатель. Посему надо держать себя в тонусе. И помогут нам в этом два сайта LeetCode и HackerRank. Оба сайта, в принципе, одинаковые, но работодателя больше возбуждает HackerRank почему-то. Может из-за названия?

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

Кому интересно, мой профиль на LeetCode и HackerRank.

Блог Евгения Жирнова