LINUX.ORG.RU

Bash архивация

 , ,


1

3

Всем доброго времени суток.Никогда не писал bash скрипты. И тут потребовалось заархивировать кучу папок по отдельности. Есть папка History, в ней кучу папок с макетами и файлами. В ручную архивировать ну малость лень так как их более 100. Начал писать скриптец и тут началась ерунда. Если есть файлы кроме папок они тоже попадают в список. Вот код:

#!/bin/bash
echo "Архиватор каталогов"
cd /media/vol1tb/history
lsfolder="./*"
echo="Список каталогов:"
for search in $(ls -d $lsfolder)
do
echo "$search"
if [ "$1" = "" ]; then
  printf "Вы хотите заархивировать каталог  $search (y/n)? [y]: "
  read choose
else
  choose="$1"

fi

if [ "$choose" = "y" ]; then
  zip -r  "$search" "$search"
else
  printf "Пропускаем $search"
fi

echo ""

if [ "$2" = "" ]; then
  printf "Удалить каталог $search (y/n)? [n]: "
  read choose
else
  choose2="$2"
fi

if [ "$choose2" = "y" ]; then
  printf "Удаление $search"
  rm -r "$search"

else
 printf "Оставляем на месте"
fi
echo clear
echo "Архивация завершена"
done

Архивация происходит, создается архив с именем папки вроде норм. Но если в папке уже есть zip файл то его тоже предлагает архивировать.

И после архивации идет запрос на удаление каталога: ввожу y, все равно выдает что оставляет каталог на месте и не удаляет.

Вопрос подскажите как передать только список директорий без файлов в родительском каталоге.

И где я туплю по удалению


Ооо, если тебе нужно обрабатывать имена файлов, содержащие пробелы и прочие символы со специальной семантикой, то тебе предстоит познать всю боль программирования shell-скриптов под unix.

Deleted
()

используй find для получения списков файлов, отвечающих условию. Например:

vadim@aquila:~$ find /usr -mindepth 1 -maxdepth 1 -type d
/usr/lib
/usr/bin
/usr/local
/usr/include
/usr/man
/usr/lib32
/usr/src
/usr/etc
/usr/libexec
/usr/share
Deleted
()

for search in $(ls -d $lsfolder)

Ошибка №1 при написании программ на языке командной оболочки.

Zmicier ★★★★★
()
Ответ на: комментарий от Deleted

А что, большой выбор?

«используй find для получения списков файлов, отвечающих условию» — больше в письме, на какое я отвечаю, ни про что нет.

Zmicier ★★★★★
()
Последнее исправление: Zmicier (всего исправлений: 1)

Если это не в чистой консоли, и не с целью изучения bash-а, то с помощью Double Commander-а это делается «несколькими щелчками мыши».

greenman ★★★★★
()
zip -r  "$search.zip" "$search"

.zip см. выше

if [ "$2" = "" ]; then
  printf "Удалить каталог $search (y/n)? [n]: "
  read choose
else
  choose2="$2"
fi

read choose вместо read choose2

futurama ★★★★★
()
Последнее исправление: futurama (всего исправлений: 1)
Ответ на: комментарий от Zmicier

Топикстартер спросил, как отфильтровать только директории. Я ответил. Тебе что надо-то? Ты топикстартер?

Deleted
()

Никогда не писал bash скрипты. И тут потребовалось заархивировать кучу папок по отдельности.

Кстати, поддержу товарища выше. Почему вы решили, что для этого надо писать программку?

Скажем, ГНУ Емакс у вас есть?

Zmicier ★★★★★
()
Ответ на: комментарий от Deleted

Топикстартер спросил, как отфильтровать только директории. Я ответил. Тебе что надо-то?

Узнать, почему вы советуете find(1) вместо подстановок в Баше?

*/, если что.

Zmicier ★★★★★
()
Последнее исправление: Zmicier (всего исправлений: 1)
Ответ на: комментарий от Zmicier

Узнать, почему вы советуете find(1) вместо подстановок в Баше?

Потому что в find можно сделать -print0 и гарантировано получить список имён файлов, вне зависимости от того, какие чудо-символы у них в составе?

Потому что */ не отличит каталог с именем * от отсутствия каталогов?

Потому что в find можно при необходимости добавить любые условия — по регэкспу, времени изменения, правам доступа — не наяривая простынки if-ов на sh?

Deleted
()
Ответ на: комментарий от Zmicier

Скажем, ГНУ Емакс у вас есть?

Будем считать, что есть.

C-x C-f /media/vol1tb/history/
m, чтобы отметить нужные каталоги
! zip -r ? ?
u, чтобы снять метки с того, что не удалять
D
Zmicier ★★★★★
()
Ответ на: комментарий от Zmicier

У меня нет графической оболочки. Плюс это только стартовый скрип очистки сервера от хлама. Мне дальше еще надо разбираться так как у меня файло помойка на 9 ТБ и файлы максимум в не по 2 гб. И дальше мне нужно будет пере архивировать каталоги в которых файл изменялись последний раз 2-3 года назад.

lokses
() автор топика
Ответ на: комментарий от Deleted

Потому что в find можно сделать -print0 и гарантировано получить список имён файлов, вне зависимости от того, какие чудо-символы у них в составе?

Разве наличие специального костыля делает предпочтительным перед бескостыльным решением?

Потому что */ не отличит каталог с именем * от отсутствия каталогов?

Ну если вы его об этом явно или неявно попросите, отключив или не включив nullglob, то конечно.

Zmicier ★★★★★
()
Ответ на: комментарий от lokses

У меня нет графической оболочки.

И что? С каких это пор Емаксу нужна графическая оболочка?

Плюс, это и удаленно должно работать не хуже:

C-x C-f /ssh:user@host:/media/vol1tb/history/

Плюс это только стартовый скрип очистки сервера от хлама.

Не распарсил.

Мне дальше еще надо разбираться так как у меня файло помойка на 9 ТБ и файлы максимум в не по 2 гб.

И что?

И дальше мне нужно будет пере архивировать каталоги в которых файл изменялись последний раз 2-3 года назад.

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

Zmicier ★★★★★
()
Ответ на: комментарий от Zmicier

Разве наличие специального костыля делает предпочтительным перед бескостыльным решением?

Запиши-ка вывод этого некостыля в пайп с сохранением целостности данных.

Ну если вы его об этом явно или неявно попросите, отключив или не включив nullglob, то конечно.

vadim@aquila:~$ man sh | grep nullglob
Status: 1
vadim@aquila:~$
Deleted
()
Ответ на: комментарий от lokses

Пробовал использовать find. не могу пока разобраться с пробелами.

Вы нашли, где прочитать про ошибку №1?

Ну, например: http://mywiki.wooledge.org/BashPitfalls#for_i_in_.24.28ls_.2A.mp3.29

Zmicier ★★★★★
()
Последнее исправление: Zmicier (всего исправлений: 2)
Ответ на: комментарий от Zmicier

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

lokses
() автор топика
Ответ на: комментарий от Deleted

Запиши-ка

Чего это мы раскомандовались?

вывод этого некостыля в пайп

С целью? Ничего подобного ни здесь, ни обычно не нужно.

А впрочем, вы, похоже, действительно, не знаете, как это сделать. Ладно, подсказываю:

$ printf '%s\0' "${dirs[@]}"
Zmicier ★★★★★
()
Ответ на: комментарий от Zmicier

Чего это мы раскомандовались?

Кто полез предъявлять претензии, тот пусть и отвечает за базар.

С целью? Ничего подобного ни здесь, ни обычно не нужно.

Ненужно — это правильный аргумент на ЛОРе. Надо было так сразу и написать, сразу бы с тобой всё было ясно.

А впрочем, вы, похоже, действительно, не знаете, как это сделать. Ладно, подсказываю:

Оооо, подсказчики. Любишь поучить людей жизни, да?

А может давай я тебе поподсказываю, как писать портабельные unix-скрипты без башизмов в каждой первой строчке? Или нет, я же не такой как ты.

В общем, в игнор.

Deleted
()
Ответ на: комментарий от lokses

А пока еще пара совершенно некритичных моментов:

printf «Вы хотите заархивировать каталог $search (y/n)? [y]: »
read choose

read -n 1 -p "Заархивировать каталог ‘$d’ (y/n)? [y]: "

echo clear

Что это?

printf «Пропускаем $search»
echo «Архивация завершена»

Для подобного рода сообщений существует вывод ошибки, не надо их кидать на стандартный вывод.

echo >&2 "Архивация завершена"

(Если у вас там такого много предполагается, функцию оформите.)

Zmicier ★★★★★
()
Ответ на: комментарий от Deleted

Кто полез предъявлять претензии

А кто у нас полез пред’являть претензии?

Ничего подобного ни здесь, ни обычно не нужно.

Ненужно — это правильный аргумент на ЛОРе.

Конечно, правильный. Товарищ, кажется, вполне ясно обрисовал, что ему нужно. И лишние обобщения и прочие сложности ему сейчас явно ни к чему.

Любишь поучить людей жизни, да?

Ой, кто бы говорил.

Оооо, подсказчики.

Конечно. Вы же на веб-форуме. Здесь так заведено: задаете вопрос (пусть и грубовато, и в офтопик слегка) — вам подсказывают. Или вы привыкли, что только у вас все все спрашивают?

А может давай я тебе поподсказываю, как писать портабельные unix-скрипты

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

Или нет, я же не такой как ты.

Да, тут бог миловал. Привычкой думать, что раз я тут такой весь из себя страдаю, то и вы все страдайте, меня не наградил.

Zmicier ★★★★★
()
Последнее исправление: Zmicier (всего исправлений: 1)
Ответ на: комментарий от Zmicier

Всем спасибо за подсказки и направления! Пошел дальше изучать маны! Всем удачи и Ребята давайте по меньше ругаться.

lokses
() автор топика
Ответ на: комментарий от lokses

Всем спасибо за подсказки и направления! Пошел дальше изучать маны!

Да пожалуйста. Только вас пока никто в направлениях не посылал. :-)

В смысле — можете смело продолжать задавать вопросы по мере их поступления.

Zmicier ★★★★★
()
Последнее исправление: Zmicier (всего исправлений: 1)

Такая простая задача и такой огромный скрипт сделал ОП и ещё больше нафлудили в топике. Кошмар.

Надо делать так:

1) перемещаешь все директории, которые не хочешь архивировать прочь. Это удобно делать с помощью mc, и перенос происходит мгновенно независимо от размера.

2) запускаешь этот простой, надёжный и короткий скрипт:

find -maxdepth 1 -mindepth 1  -type d -print0 | xargs -0 -P `nproc` -I{} sh -c 'echo архвируем "{}"; tar --force-local -caf "{}.tar.bz2" "{}" && rm -rf "{}" && echo успешно сархивировали "{}" || echo ОШИБКА при работе с "{}"'
Он найдёт директории непосредственно в текущей, сожмёт их, удалит если не было ошибкок и всё это параллельно. Все символы в именах, кроме двойных кавычек поддерживаются (пробелы, двоеточия - без проблем)

legolegs ★★★★★
()

Главная ошибка этого скрипта даже не choose2, а в том, что вызов «script y n» когда-нибудь случайно перепутается в «script n y» и вы удалите всё без архивирования. Не дело скрипту, который архивирует удалять без архивирования. Опция удаления должна быть опциональна к архивированию. И таки оформлена не в виде безличного «y/n» , а стандартным видом опций: -a -d.

vodz ★★★★★
()
Ответ на: комментарий от legolegs

Спасибо за скрипт. только я не могу понять параметр для архивации caf. Так как мне нужно архивировать в zip

lokses
() автор топика
Ответ на: комментарий от lokses
tar --force-local -caf "{}.tar.bz2" "{}"

заменяется на

zip -r "{}.zip" "{}"
. Но зачем зип мне не понятно, он же хуже жмёт, чем те компрессоры, которые можно использовать с tar

legolegs ★★★★★
()
Ответ на: комментарий от legolegs

Архивы с макетами а на винде zip по стандарту открывает.

lokses
() автор топика
Ответ на: комментарий от lokses

legolegs, На самом деле нет никаких сложностей и для кавычек в имени:

#!/bin/bash

arch=0
del=0
use_ard=0

usage() {
	echo "Usage $0 [-a[-d]]" 2>&1
	exit 2
}

while getopts ":adX" o; do
    case "$o" in
    a) arch=1
       ;;
    d) del=1
       ;;
    X) use_ard=1;;
    *) usage;;
    esac
done
shift $((OPTIND-1))

ad() {
	for i; do
		if [[ $arch -eq 0 ]]; then
			a=
			read -p "Заархивировать каталог $i (y/n)? [y]: " a
			case "${a:=y}" in
			Y|[yY][eE][sS]) a=y ;;
			esac
		else
			a=y
		fi
		if [[ $a == y ]]; then
			echo zip -r `date "+%F"`.zip "$i"
			if [[ $del -eq 0 ]]; then
				a=
				read -p "Удалить каталог $i (y/n)? [n]: " a
				case "${a:=n}" in
				Y|[yY][eE][sS]) a=y ;;
				esac
			else
				a=y
			fi
			[[ $a == y ]] && echo rm -rf "$i"
		fi
	done
}

if [[ $use_ard -eq 1 ]]; then
	ad "$@"
else
	[[ arch -eq 1 ]] && a1=-a || a1=
	[[ del -eq 1 ]] && a2=-d || a2=
	find / -mindepth 1 -maxdepth 1 -type d -exec "$0" $a1 $a2 -X {} \;
fi

vodz ★★★★★
()
Последнее исправление: vodz (всего исправлений: 2)
Ответ на: комментарий от legolegs

Но зачем зип мне не понятно, он же хуже жмёт, чем те компрессоры, которые можно использовать с tar

Степень компрессии тут на вторых ролях. Tar - убогое говнище без индекса файлов, и его лучше избегать. Искать файл в 200ГБ-ом tar-архиве, да еще сжатом - то еще занятие. Этого надо в корне избегать: не пользоваться таром, если тебе не на ленту записывать (то, для чего он и был сделан, собственно).

Eсли TC устраивает zip, с его возможными проблемами хранения некоторых имен файлов в некоторых версиях формата, - ОК.

Иначе, пусть смотрит на squashfs или Plzip (http://www.nongnu.org/lzip/plzip.html )

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от Deleted

Дело в том что. Я уже в течении года говорил начальству за увеличение объема файлопомойки или перебора файлов для удаления и очистки. К сожалению меня не услышали. На целостность файлов мне в дальнейшем похрен. Не хотят выделять деньги или перебирать файлы то пусть получают. Я бы вообще по удалял бы файлы которым более 2-х лет не делали изменения и не парился. Но мне же не дают добро на это.

lokses
() автор топика
Ответ на: комментарий от Deleted

И так как Windows 10 довольно не плохо по стандарту работает с zip то решено в данный тип архивировать

lokses
() автор топика
Ответ на: комментарий от vodz

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

legolegs ★★★★★
()
Ответ на: комментарий от legolegs

Ты говоришь, что нет сложностей, а я вижу программный продукт аж на целый экран.

Ну это был вариант write-only.

Он так велик, что ты забыл убрать эхо перед зип.

Да не, я не забыл, удаляющие скрипты слишком неудобные для экспериментов.

потому что скрипт короткий его проще прочитать.

Ну, Ok. Упростил и добавил функционала. Теперь можно запускать с набором каталогов непосредственно.

#!/bin/bash

usage() {
	echo "Usage $0 [-a[-d]] [-X dirs...]" 2>&1
	exit 2
}

arch= ; del= ; use_ad=0
while getopts ":adADX" o; do
    case "$o" in
    a) arch=-a ;;
    d) del=-d ;;
    X) use_ad=1;;
    [AD]) ;;
    *) usage;;
    esac
done
shift $((OPTIND-1))

yn() {
	local y
	[[ -n $1 && $1 != 0 && $1 != [nN]* ]] && y=1 || y=0
	if [[ $y -eq 0 ]]; then
		local a
		read -n1 -p "$2 (y/n)? [$3]: " a
		case "$a" in
		[yY]) echo ; y=1 ;;
		?) echo ;;
		*) [[ $3 == [yY]* ]] && y=1;;
		esac
	fi
	return $((y==0))
}

ad() {
	for i; do
		if yn "$arch" "Заархивировать каталог $i" y; then
			echo zip -r "$zip" "$i"
			yn "$del" "Удалить каталог $i" n && echo rm -rf "$i"
		fi
	done
}

if [[ $use_ad -eq 1 ]]; then
	zip=`date "+%F"`.zip
	ad "$@"
else
	[[ $# -ne 0 ]] && usage
	find / -mindepth 1 -maxdepth 1 -type d -exec "$0" ${arch:--A} ${del:--D} -X {} \;
fi

vodz ★★★★★
()
Ответ на: комментарий от Deleted

Искать файл в 200ГБ-ом tar-архиве, да еще сжатом - то еще занятие.

Кстати, да. Всегда меня брало любопытство, почему до сих пор не перешли от архивирования и последующего сжатию к сжатию сначала и архивированию потом.

Обратной совместимостью это обладает сполна.

Вы не встречали авторитетных суждений по этому вопросу?

Zmicier ★★★★★
()
Последнее исправление: Zmicier (всего исправлений: 1)
Ответ на: комментарий от Zmicier

К сожалению, не встречал. Моя быстрая мысль на этот счет - надежда на solid сжатие, общий словарь и все дела. (но это не авторитетно :)

Кстати, упомяну ссылку http://www.nongnu.org/lzip/xz_inadequate.html - это оффтоп оффтопа, но я её как то прочитал, потом потерял (а в поиске она не на первых страницах у меня, почему то), и теперь пусть будет еще одно упоминание, не повредит, как минимум кто-то прочитает новый. (Ты может уже и читал)

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от Deleted

К сожалению, не встречал. Моя быстрая мысль на этот счет - надежда на solid сжатие, общий словарь и все дела. (но это не авторитетно :)

http://pubs.opengroup.org/onlinepubs/7908799/xcu/tar.html - найдите тут сжатие вообще. :)

vodz ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.