Isquariel 07.06.2012 21:03

Скрипты на bashПереархивируем архивы в папке

В процессе изучения 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 ./ # Запускаем просмотр текущей папки



Хотелось бы узнать, что я делаю не так при данных требованиях.


Тэги: 7zip bash
+ 4 -
Похожие Поделиться

cppmm 07.06.2012 21:28 #
Код определения полного пути к директории(начиная с 60-ой строки) лучше заменить командой realpath.
Самописную рекурсию в функции listdir я бы реализовал через find. Проще и надёжнее.
В функции convert можно обойтись без временной директории. Сейчас не помню возможностей 7z, а смотреть лень, но, например для bzip2/gzip это выглядело бы примерно так:
1
gzip -d files.tar.gz | bzip2 > files.tar.bz2 && rm files.tar


Это так, именно по скрипту.
Ну а вообще по-моему это всё тем же find'ом можно в одну строку написать. :)
Типа: find ./ -type f -name "*.gz" -exec ...
Isquariel 07.06.2012 22:59 #
Я так понимаю, решение через find и через gzip, которые ты написал, работают только для одного типа файлов, ну или нужно прописывать все типы ручками. А мне нужно, чтобы оно ВСЕ архивы, понимаемые 7zip’ом переводило в один тип.
cppmm 07.06.2012 23:10 #
Да без проблем.
find ./ -name "*.bz2" -o -name "*.gz"
Ну и т.д. Вписать все нужные типы архивов.
Isquariel 08.06.2012 09:55 #
Поняла, спасибо.
mealsforall 07.06.2012 23:49 #
Поставил плюсик просто за хороший стиль и красивое оформление скрипта.
ananas 08.06.2012 07:19 #
рекурсия в listdir не нужна, проще find дергать. echo + read имеет смысл заменить на read -p, да и expr на башевский $((..)), раз уж хешбэнг - #! /bin/bash
ananas 08.06.2012 11:10 #
хотя даже expr вообще не нужен. o="${i%.*}.$TYPE"
ananas 08.06.2012 07:23 #
и rearchiver.log имеет смысл обнулять вначале
blackraven 08.06.2012 12:56 #
Кажется, в женском полку вилинукса прибыло? :)
Isquariel 11.06.2012 20:57 #
Угу.