Linux zip и исключение директории в Bash-скрипте

Вопрос или проблема

Я пытаюсь написать bash/shell скрипт, чтобы заархивировать конкретную папку и игнорировать определенные подкаталоги в этой папке.

Вот папка, которую я пытаюсь заархивировать “sync_test5“:

введите описание изображения здесь

Мой bash скрипт генерирует список игнорируемых элементов (основанный на) и вызывает функцию zip следующим образом:

#!/bin/bash

SYNC_WEB_ROOT_BASE_DIR="/home/www-data/public_html"
SYNC_WEB_ROOT_BACKUP_DIR="sync_test5"
SYNC_WEB_ROOT_IGNORE_DIR="dir_to_ignore dir2_to_ignore"

ignorelist=""
if [ "$SYNC_WEB_ROOT_IGNORE_DIR" != "" ];
then
    for ignoredir in $SYNC_WEB_ROOT_IGNORE_DIR
    do
        ignorelist="$ignorelist $SYNC_WEB_ROOT_BACKUP_DIR/$ignoredir/**\*"
    done
fi

FILE="$SYNC_BACKUP_DIR/$DATETIMENOW.website.zip"
cd $SYNC_WEB_ROOT_BASE_DIR;
zip -r $FILE $SYNC_WEB_ROOT_BACKUP_DIR -x $ignorelist >/dev/null
echo "Готово"

Теперь этот скрипт выполняется без ошибок, однако он не игнорирует/исключает директории, которые я указал.

Итак, я заставил shell скрипт вывести команду, которую он пытался запустить, которая была:

zip -r 12-08-2014_072810.website.zip sync_test5 -x  sync_test5/dir_to_ignore/**\* sync_test5/dir2_to_ignore/**\*

Теперь, если я запущу вышеуказанную команду напрямую в putty вот так, она работает:

введите описание изображения здесь

Так почему же мой shell скрипт не исключает, как задумывалось? Команда, которая выполняется, идентична (в shell и putty напрямую).

Я не вижу, что вы пытаетесь добиться с помощью "**\*" в списке исключений, но как я понимаю, -x исключает файлы, имена которых соответствуют шаблону, и не учитывает директории, в которых они находятся.

Самый простой способ исключить директории – временно убрать разрешение на выполнение с них, например:-

chmod -x ...
zip ...
chmod +x ...

Просто убедитесь, что вы восстанавливаете разрешение на выполнение, если вы прерваете скрипт по какой-либо причине.

Согласно этому ответу, https://superuser.com/a/496903/356580, вам нужно что-то вроде:

ignorelist=""
if [ "$SYNC_WEB_ROOT_IGNORE_DIR" != "" ];
then
    for ignoredir in $SYNC_WEB_ROOT_IGNORE_DIR
    do
        ignorelist="$ignorelist \"$SYNC_WEB_ROOT_BACKUP_DIR/$ignoredir/*\""
    done
fi

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

ignorelist="$ignorelist $SYNC_WEB_ROOT_BACKUP_DIR/$ignoredir/\\*"

Но каждому свое. Что вы хотите, так это чтобы команда выглядела как одна из приведенных ниже, когда она выполняется через замену:

zip -r sync_test.zip sync_test -x sync_test/dir_to_ignore/\* sync_test/dir2_to_ignore/\*
zip -r sync_test.zip sync_test -x "sync_test/dir_to_ignore/*" "sync_test/dir2_to_ignore/*"

Таким образом, символ звездочка отправляется в zip, и нет файловой глобализации на командной строке.

Ответ или решение

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

Шаги по исключению директорий из архивации:

  1. Определите переменные: В скрипте вы уже определили основные переменные, такие как SYNC_WEB_ROOT_BASE_DIR, SYNC_WEB_ROOT_BACKUP_DIR и SYNC_WEB_ROOT_IGNORE_DIR. Убедитесь, что они содержат правильные значения.

  2. Формирование списка игнорируемых директорий: В списке игнорируемых директорий, который вы формируете в цикле, важно правильно установить синтаксис для шаблонов исключений. Вместо /**/* используйте /*, чтобы исключить все файлы и подкаталоги внутри указанных директорий.

  3. Обработка переменной $(ignorelist): Следует правильно формировать ignorelist, добавляя вокруг каждой строки кавычки, чтобы избежать проблем с пробелами и специальными символами.

Обновленный скрипт:

#!/bin/bash

# Определите базовые и целевые директории
SYNC_WEB_ROOT_BASE_DIR="/home/www-data/public_html"
SYNC_WEB_ROOT_BACKUP_DIR="sync_test5"
SYNC_WEB_ROOT_IGNORE_DIR="dir_to_ignore dir2_to_ignore"

# Инициализация списка игнорируемых директорий
ignorelist=""
if [ -n "$SYNC_WEB_ROOT_IGNORE_DIR" ]; then
    for ignoredir in $SYNC_WEB_ROOT_IGNORE_DIR; do
        ignorelist="$ignorelist \"$SYNC_WEB_ROOT_BACKUP_DIR/$ignoredir/*\""
    done
fi

# Определите файл архива
DATETIMENOW=$(date +"%Y-%m-%d_%H-%M-%S")
FILE="$SYNC_WEB_ROOT_BASE_DIR/$DATETIMENOW.website.zip"

# Перейдите в целевую директорию и выполните команду zip
cd $SYNC_WEB_ROOT_BASE_DIR || exit
zip -r "$FILE" "$SYNC_WEB_ROOT_BACKUP_DIR" -x $ignorelist &>/dev/null

echo "Создание архива завершено"

Объяснение изменений:

  1. Проверка переменной: Используйте -n для проверки, что строка не пустая. Это более надежный способ, чем сравнение с пустой строкой.

  2. Формирование ignorelist: Добавление кавычек вокруг каждого пути помогает предотвратить проблемы с пробелами в именах директорий.

  3. Использование &>/dev/null: Эта конструкция отправляет как стандартный вывод, так и вывод ошибок в null, тем самым очищая экран от лишней информации.

  4. Определение даты и времени: Мы добавили генерацию метки времени в переменной DATETIMENOW, чтобы файл архива имел уникальное имя.

Заключение:

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

Оцените материал
Добавить комментарий

Капча загружается...