В процессе изучения bash пишу программу, которая переархивирует все архивы в архивы заданного типа (с помощью 7zip). Используется как диалоговый режим, так и запуск с параметрами.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
|
#!/bin/bash
# Эта функция выводит руководство
function usage() { echo echo "Usage: bash rearchive [options]" echo echo " -R рекурсивно" echo " -t <type> тип архива (по умолчанию 7z)" echo " -o <dir> папка, в которую складывать архивы (если необходимо)" echo " -f перезаписывать файлы, если файл с таким именем уже существует" echo " -h показать это руководство" echo "Запускайте этот скрипт в той папке, в которой надо проверить архивы" echo exit }
# Задаём значения по умолчанию
RECURSIVE=0 # Не рекурсивно TYPE="7z" # Тип архива по умолчанию OUTPUT="" # Папка вывода по умолчанию FOCRE="-i" # Спрашивать подверждение при замене файлов
if [ "$1" = "" ]; then # Если аргументов нет, то echo "Введите тип архива (7z, zip и др):" read TYPE # Считываем тип архива echo "Введите папку, в которую нужно поместить архивы (иначе оставьте пустым):" read OUTPUT # Считываем папку вывода a="" until [ "$a" = "y" ] || [ "$a" = "n" ]; do echo "Обойти папку рекурсивно?(y/n):" read a # Считываем рекурсию if [ "$a" = "y" ]; then # Если ответили y то RECURSIVE=1 # Делаем рекурсивно fi done a="" until [ "$a" = "y" ] || [ "$a" = "n" ]; do echo "Перезаписывать файлы в случае совпадения имён?(y/n):" read a # Считываем подтверждение if [ "$a" = "y" ]; then FORCE="-f" # Если ответили да, то убираем подтверждение fi done else while getopts "t:o:hfR" OPTION; do # Считываем опции case "$OPTION" in t) TYPE="$OPTARG" ;; # Тип архива o) OUTPUT="$OPTARG" ;; # Папка вывода R) RECURSIVE=1 ;; # Рекурсия h) usage ;; # Выводим справку f) FORCE="-f" ;; # Убираем подтверждения *) usage ;; # Выводим справку esac done fi
if [ -n "$OUTPUT" ]; then # Если имя папки вывода не пусто t=`pwd` # Сохраняем текущее положение cd "$OUTPUT" # Заходим в папку вывода OUTPUT=`pwd` # Запоминаем полный путь до неё cd $t # Заходим обратно echo "Все архивы будут помещены в папку $OUTPUT" fi
# Эта функция просматривает папку, # переводит все архивы в ней, # заходит во внутренние папки, если это необходимо
function listdir() { cd $1 # Заходим в папку, переданную в первом аргументе if [ "$1" = "./" ]; then # Если это текущая папка path=$1 # Сохраняем в этой переменной символ "./" else # Иначе path=$2$1"/" # Сохраняем путь до этой папки оттуда, откуда мы начали обход fi for i in *; do # Для всех файлов в папке if [ -f "$i" ]; then # Если это файл if [ "`7z t $i | grep Everything`" = "Everything is Ok" ]; then # И если 7z считает его архивом convert $i $path # Конвертируем его fi fi if [ "$RECURSIVE"="1" ]; then # Если рекурсивно if [ -d "$i" ]; then # То проверяем, не папка ли у нас listdir $i $path # И если папка, то заходим в неё и выполняем в ней эту же функцю fi fi done cd .. # Выходим обратно }
# Эта функция конвертирует архив
function convert { local i="$1" # Запоминаем имя архива local path="$2" # Запоминаем его положение local o=`expr match "$i" '\(.*\)\.'`"."$TYPE # Получаем имя нового архива if [ "$i" != "$o" ]; then # Если имя нового и старого архивов не совпадает echo "$path$i будет преобразован в $o" # Выводим сообщение local t=`mktemp -d` # Создаём временную папку 7z x "$i -o$t" >> rearchiver.log # Распаковываем в неё архив 7z a "$t/$o $t/*" >> rearchiver.log # Архивируем эти файлы if [ -n "$OUTPUT" ]; then # Если папка вывода не пуста mv "$FORCE" -- "$t/$o $OUTPUT" 2>> rearchiver.log # Перемещаем архив в неё else # Иначе mv "$FORCE" -- "$t/$o" ./ 2>> rearchiver.log # Перемещаем архив на место fi rm -R $t # Удаляем временную папку else # А если архив новый совпадает со старым echo "$path$i является архивом данного типа" # Сообщаем об этом if [ -n "$OUTPUT" ]; then # И если папка вывода не пуста cp "$FORCE" -- "$i $OUTPUT" 2>> rearchiver.log # Копируем его туда fi fi }
listdir ./ # Запускаем просмотр текущей папки
|
Хотелось бы узнать, что я делаю не так при данных требованиях.
Самописную рекурсию в функции listdir я бы реализовал через find. Проще и надёжнее.
В функции convert можно обойтись без временной директории. Сейчас не помню возможностей 7z, а смотреть лень, но, например для bzip2/gzip это выглядело бы примерно так:
Это так, именно по скрипту.
Ну а вообще по-моему это всё тем же find'ом можно в одну строку написать. :)
Типа: find ./ -type f -name "*.gz" -exec ...