Скрипт архивировния по определенным правилам (Вопросы + критика)

На самом деле это единственный раздел про unix на этом форуме

Модераторы: /dev/random, Модераторы разделов

Аватара пользователя
Voral
Сообщения: 1205
ОС: Debian Wheezy (amd64)

Скрипт архивировния по определенным правилам

Сообщение Voral »

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

И два вопроса:
1. Есть строка которая парсит название файла "выкусывая" оттуда определенный фрагмент (ID архива). В регулярном выражении явно задано расширение (7z). Однако хотелось бы его задавать переменной $ARCEXT. когда подставляю перестает работать эта команда

Код: Выделить всё

OLDID=`echo $OLDFILE | sed -rn 's/[a-zA-Z]+[0-9]+_([0-9]{2}).7z/\1/p'`;

2. Есть строка которая ищет файлы новее заданного и помещает их в архив, а так же выводит имя файла на экран. find возвращает найденные файлы начиная с "./". Но архиватор (7z) если получает имя файла в таком виде, то помещает в архив без относительного пути. Т.е. мне приходится в этой же строке убирать "./" и тогда архиватор сохраняет вложенные каталоги (если найденный файл находится в них).
В итоге это строчка получилась довольно громоздкой. Вчитывался в маны 7z, find, sed, xargs - лучше решения не нашел. Есть ли оно?

Код: Выделить всё

find ./ -type f -cnewer ../$OLDFILE | while read i; do (echo $i;echo $i | sed -rn 's/\.\///p' | xargs -i $ARCLINE ../$NEWFILE '{}' > /dev/null \;) done;


Весь скрипт полностью

Код: Выделить всё

#!/bin/sh
# Скрипт архивирования каталога и обновлений
# Версия: 1.1 от 31-03-2010
# Автор: Воробьев Александр
# url: http://va-soft.com/
#
# Скрипт формирует два архива:
# 1. Полный архив каталога с именем <dir><date>
# 2. Архив новых файлов с момента предыдущего архивировния с именем <dir><date>_<id>
# В именах файлов:
#     <dir>    - имя родительского каталога
#    <date>    - дата архива в формате  YYYYMMDD (год 4 знака, месяц 2 знака, день 2 знака)
#    <id>    - порядковый номер архива 2 знака
# Если предыдущий архив обновлений отсутствует, то он создается копированием полного архива
# После создания архива обновлений старый архив обновленй удаляется
#
# Пример дерева каталогов
# myproject/                - родительский каталог
# myproject/site/            - целевой каталог для архивирования
# myproject/site/samefile.css
# myproject/site/samefile.html
# myproject/myproject20100101.7z    - полный архив каталога
# myproject/myproject20100101_02.7z    - архив обновлений
# myproject/news.sh            - данный скрипт

# Команда архивирования
ARCLINE="7z a -R";
# Расширение архивов
ARCEXT="7z";
# Целевой каталог для архивирования
SUBDIR="site";

CURDIR=`pwd | sed -rn "s/.*\/([^\/]*)$/\1/gp"`;
CURDATE=`date +%Y%m%d`;
OLDFILE=`find . -type f -name $CURDIR????????_??.$ARCEXT | sed -r 's/\.\///'`
cd $SUBDIR;
$ARCLINE ../$CURDIR$CURDATE.$ARCEXT > /dev/null
if [ "$OLDFILE" == "" ]
then
    cp ../$CURDIR$CURDATE.$ARCEXT ../$CURDIR${CURDATE}_01.$ARCEXT
else
    OLDDATE=`echo $OLDFILE | sed -rn 's/[a-zA-Z]+([0-9]+).*/\1/p'`;
    if [ "$OLDDATE" == "$CURDATE" ]
    then
        OLDID=`echo $OLDFILE | sed -rn 's/[a-zA-Z]+[0-9]+_([0-9]{2}).7z/\1/p'`;
        NEWID=`expr $OLDID + 1`
    else
        NEWID=1;
    fi
    NEWFILE=`printf "%s%s_%02d.$ARCEXT" $CURDIR $CURDATE $NEWID`;
# Старый вариант find ./ -type f -cnewer ../$OLDFILE | while read i; do (echo $i;echo $i | sed -rn 's/\.\///p' | xargs -i $ARCLINE ../$NEWFILE '{}' > /dev/null \;) done;
    find ./ -type f -cnewer ../$OLDFILE  -printf "%P\n" | while read i; do (echo $i; $ARCLINE ../$NEWFILE $i > /dev/null \;) done;
    if [ -f ../$NEWFILE ]
    then
        rm ../$OLDFILE;
    fi;
fi;
cd ..;


upd Исправлена самая длинная строка благодаря наводке drBatty
То что не убивает нас, делает нас сильнее! © Ницше.
When life puts you in tough situations, don’t say "why me". Just say "try me © ?
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: Скрипт архивировния по определенным правилам

Сообщение drBatty »

Voral писал(а):
31.03.2010 18:26
Однако хотелось бы его задавать переменной $ARCEXT. когда подставляю перестает работать эта команда

такие сложные строчки можно сначала сформировать, а потом выполнить с помощью eval.
Voral писал(а):
31.03.2010 18:26
find возвращает найденные файлы начиная с "./"

man find про -printf.

И ещё:

Код: Выделить всё

OLDFILE=`find . -type f -name $CURDIR????????_??.$ARCEXT | sed -r 's/\.\///'`

видите откуда взялась точка? Вы её сами поставили после команды find :)


ЗЫЖ у меня только одно замечание - одностроки рулят только для вас, и в конкурсах непонятного программирования :(
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
Voral
Сообщения: 1205
ОС: Debian Wheezy (amd64)

Re: Скрипт архивировния по определенным правилам

Сообщение Voral »

drBatty писал(а):
31.03.2010 18:35
man find про -printf.

Блин несколько раз читал сегодня - только сейчас нашел
-printf "%P\n"

drBatty писал(а):
31.03.2010 18:35
ЗЫЖ у меня только одно замечание - одностроки рулят только для вас, и в конкурсах непонятного программирования :(

Понял.
Точнее не совсем :blush:
Можете на примере какой либо строки показать, что тут можно "разбить" или просто намекнуть....
То что не убивает нас, делает нас сильнее! © Ницше.
When life puts you in tough situations, don’t say "why me". Just say "try me © ?
Спасибо сказали:
Аватара пользователя
SLEDopit
Модератор
Сообщения: 4823
Статус: фанат консоли (=
ОС: GNU/Debian, RHEL

Re: Скрипт архивировния по определенным правилам

Сообщение SLEDopit »

Voral писал(а):
31.03.2010 18:26
Однако хотелось бы его задавать переменной $ARCEXT. когда подставляю перестает работать эта команда
Конечно, в одинарных кавычках не происходит подстановки переменных. Вот так будет работать:

Код: Выделить всё

OLDID=`echo $OLDFILE | sed -rn "s/.*_([0-9]{2}).$ARCEXT/\1/p"`;

Voral писал(а):
31.03.2010 18:26
CURDIR=`pwd | sed -rn "s/.*\/([^\/]*)$/\1/gp"`;
Имхо, проще:

Код: Выделить всё

CURDIR=`basename $PWD`;

Voral писал(а):
31.03.2010 18:26
sed -rn 's/[a-zA-Z]+[0-9]+_([0-9]{2}).7z/\1/p'
В принципе вот это [a-zA-Z]+[0-9]+ можно заменить на .*
Voral писал(а):
31.03.2010 18:26
if [ -f ../$NEWFILE ]
then
rm ../$OLDFILE;
fi;
В простейших случаях такую конструкцию можно заменить на следующую:

Код: Выделить всё

[ -f ../$NEWFILE ] && rm ../$OLDFILE
да и еще кое-где тоже.
Voral писал(а):
31.03.2010 18:26
find ./ -type f -cnewer ../$OLDFILE -printf "%P\n" | while read i; do (echo $i; $ARCLINE ../$NEWFILE $i > /dev/null \;) done;
ну у find есть же опция exec, есть xargs в конце концов. Так же гораздо производительнее.
UNIX is basically a simple operating system, but you have to be a genius to understand the simplicity. © Dennis Ritchie
The more you believe you don't do mistakes, the more bugs are in your code.
Спасибо сказали:
watashiwa_daredeska
Бывший модератор
Сообщения: 4038
Статус: Искусственный интеллект (pre-alpha)
ОС: Debian GNU/Linux

Re: Скрипт архивировния по определенным правилам

Сообщение watashiwa_daredeska »

Код: Выделить всё

- if [ "$OLDFILE" == "" ]
+ if [ -z "$OLDFILE" ]

- if [ "$OLDDATE" == "$CURDATE" ]
- if [ "x$OLDDATE" = "x$CURDATE" ]

- NEWID=`expr $OLDID + 1`
+ NEWID=$((OLDID+1))

- find ./ -type f -cnewer ../$OLDFILE  -printf "%P\n" | while read i; do (echo $i; $ARCLINE ../$NEWFILE $i > /dev/null \;) done;
+ find ./ -type f -cnewer ../$OLDFILE  -printf "%P\n" | tee | xargs -n 1 $ARCLINE ../$NEWFILE > /dev/null


cd ..; на последней строке скрипта не нужен.

Очень много лишних «;» — они не нужны на концах строк.

Voral писал(а):
31.03.2010 18:26
когда подставляю перестает работать эта команда
Покажите, как подставляете, тогда можно будет чем-то помочь.

JFYI: http://codereview.appspot.com/
Спасибо сказали:
Аватара пользователя
Voral
Сообщения: 1205
ОС: Debian Wheezy (amd64)

Re: Скрипт архивировния по определенным правилам

Сообщение Voral »

SLEDopit писал(а):
31.03.2010 19:28
Voral писал(а):
31.03.2010 18:26
find ./ -type f -cnewer ../$OLDFILE -printf "%P\n" | while read i; do (echo $i; $ARCLINE ../$NEWFILE $i > /dev/null \;) done;
ну у find есть же опция exec, есть xargs в конце концов. Так же гораздо производительнее.

Я не осилил с их помощью выполнить две команды. Хотя стоп. После исправления скрипта (этой строки) до процитированного вида.Могу.
Два раза -exec?


watashiwa_daredeska писал(а):
31.03.2010 19:36
Voral писал(а):
31.03.2010 18:26
когда подставляю перестает работать эта команда
Покажите, как подставляете, тогда можно будет чем-то помочь.

Эту проблему решил благодаря SLEDopit - кавычки на двойные поменял
То что не убивает нас, делает нас сильнее! © Ницше.
When life puts you in tough situations, don’t say "why me". Just say "try me © ?
Спасибо сказали:
Аватара пользователя
SLEDopit
Модератор
Сообщения: 4823
Статус: фанат консоли (=
ОС: GNU/Debian, RHEL

Re: Скрипт архивировния по определенным правилам

Сообщение SLEDopit »

Voral писал(а):
31.03.2010 19:43
Два раза -exec?
Так echo не нужно будет выполнять. printf и так все напечатает.
А если что, то можно и два раза exec.
UNIX is basically a simple operating system, but you have to be a genius to understand the simplicity. © Dennis Ritchie
The more you believe you don't do mistakes, the more bugs are in your code.
Спасибо сказали:
Аватара пользователя
Voral
Сообщения: 1205
ОС: Debian Wheezy (amd64)

Re: Скрипт архивировния по определенным правилам

Сообщение Voral »

watashiwa_daredeska писал(а):
31.03.2010 19:36

Код: Выделить всё

- NEWID=`expr $OLDID + 1`
+ NEWID=$((OLDID+1))

Выдало

Код: Выделить всё

./news.sh: line 49: 08: value too great for base (error token is "08")
То что не убивает нас, делает нас сильнее! © Ницше.
When life puts you in tough situations, don’t say "why me". Just say "try me © ?
Спасибо сказали:
watashiwa_daredeska
Бывший модератор
Сообщения: 4038
Статус: Искусственный интеллект (pre-alpha)
ОС: Debian GNU/Linux

Re: Скрипт архивировния по определенным правилам

Сообщение watashiwa_daredeska »

Voral писал(а):
31.03.2010 19:47
./news.sh: line 49: 08: value too great for base (error token is "08")

Код: Выделить всё

- OLDID=`echo $OLDFILE | sed -rn 's/[a-zA-Z]+[0-9]+_([0-9]{2}).7z/\1/p'`;
+ OLDID=`echo $OLDFILE | sed -rn 's/[a-zA-Z]+[0-9]+_0*([0-9]{2}).7z/\1/p'`
Числа, начинающиеся с «0» считаются записанными в 8-ичной системе. «8» — неправильная цифра :)
Спасибо сказали:
Аватара пользователя
Voral
Сообщения: 1205
ОС: Debian Wheezy (amd64)

Re: Скрипт архивировния по определенным правилам

Сообщение Voral »

SLEDopit писал(а):
31.03.2010 19:45
Так echo не нужно будет выполнять. printf и так все напечатает.
А если что, то можно и два раза exec.

А пожалуй нет. Это на экран пойдет форматированый. а в команду пойдет с точкой в начале. Попробовал на:

Код: Выделить всё

find -name *.jpg -printf "%P\n" -exec echo {} \;

То что не убивает нас, делает нас сильнее! © Ницше.
When life puts you in tough situations, don’t say "why me". Just say "try me © ?
Спасибо сказали:
Аватара пользователя
Voral
Сообщения: 1205
ОС: Debian Wheezy (amd64)

Re: Скрипт архивировния по определенным правилам

Сообщение Voral »

watashiwa_daredeska писал(а):
31.03.2010 19:36
- find ./ -type f -cnewer ../$OLDFILE -printf "%P\n" | while read i; do (echo $i; $ARCLINE ../$NEWFILE $i > /dev/null \;) done;
+ find ./ -type f -cnewer ../$OLDFILE -printf "%P\n" | tee | xargs -n 1 $ARCLINE ../$NEWFILE > /dev/null[code]

Тут архивируются все файлы а не только новые. К тому же пропал вывод имен архивируемых файлов. Если убрать перенаправление в null, то 7z их выводит. По выводу я так понимаю он один раз запускается. (В моем случае для каждого файла).
Если я правильно понимаю. Если файлов много будет для архивирования, то можно напороться на "переполнение" командной строки?

Упс. Время много. Всем спасибо. Буду разбираться дальше завтра.


То что не убивает нас, делает нас сильнее! © Ницше.
When life puts you in tough situations, don’t say "why me". Just say "try me © ?
Спасибо сказали:
Аватара пользователя
SLEDopit
Модератор
Сообщения: 4823
Статус: фанат консоли (=
ОС: GNU/Debian, RHEL

Re: Скрипт архивировния по определенным правилам

Сообщение SLEDopit »

Voral писал(а):
31.03.2010 19:51
а в команду пойдет с точкой в начале.
чем так принципиально отсутствие этой точки? 7z и так и так прекрасно все архивирует.

Код: Выделить всё

 $ 7z a -R 1.7z 1

7-Zip 9.04 beta  Copyright (c) 1999-2009 Igor Pavlov  2009-05-30
p7zip Version 9.04 (locale=en_US.UTF-8,Utf16=on,HugeFiles=on,2 CPUs)
Scanning

Creating archive 1.7z

Compressing  scripts/1
Compressing  1

Everything is Ok

 $ 7z a -R 1.7z ./2

7-Zip 9.04 beta  Copyright (c) 1999-2009 Igor Pavlov  2009-05-30
p7zip Version 9.04 (locale=en_US.UTF-8,Utf16=on,HugeFiles=on,2 CPUs)

Scanning

Updating archive 1.7z

Compressing  2

Everything is Ok
UNIX is basically a simple operating system, but you have to be a genius to understand the simplicity. © Dennis Ritchie
The more you believe you don't do mistakes, the more bugs are in your code.
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: Скрипт архивировния по определенным правилам

Сообщение drBatty »

SLEDopit писал(а):
31.03.2010 19:28
Конечно, в одинарных кавычках не происходит подстановки переменных. Вот так будет работать:
Код
OLDID=`echo $OLDFILE | sed -rn "s/.*_([0-9]{2}).$ARCEXT/\1/p"`;

как-бы безопаснее что-то вроде 's/.*_([0-9]{2}).'"$ARCEXT"'/\1/p'
или так не получится?

SLEDopit писал(а):
31.03.2010 20:22
чем так принципиально отсутсвие этой точки? 7z и так и так прекрасно все архивирует.

не знаю как 7z, а православный tar - легко.
Voral писал(а):
31.03.2010 20:10
Если я правильно понимаю. Если файлов много будет для архивирования, то можно напороться на "переполнение" командной строки?

с xargs и потоками - никак нельзя. xargs будет кормить команду максимально возможным числом файлов. А вот 7z * - тут пожалуйста, звёздочка развернётся во всё, и часть файлов будет молча потеряна.
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
Voral
Сообщения: 1205
ОС: Debian Wheezy (amd64)

Re: Скрипт архивировния по определенным правилам

Сообщение Voral »

SLEDopit писал(а):
31.03.2010 20:22
этой точки? 7z и так и так прекрасно все архивирует.

Принципиально. Если с точкой в начале он архивирует вообще без путей. Все валит в кучу. Если без оной - нормально архивирует с подкаталогами
Сегодня долго бился с этим - так "фишки" и не понял
То что не убивает нас, делает нас сильнее! © Ницше.
When life puts you in tough situations, don’t say "why me". Just say "try me © ?
Спасибо сказали:
watashiwa_daredeska
Бывший модератор
Сообщения: 4038
Статус: Искусственный интеллект (pre-alpha)
ОС: Debian GNU/Linux

Re: Скрипт архивировния по определенным правилам

Сообщение watashiwa_daredeska »

Voral писал(а):
31.03.2010 20:10
К тому же пропал вывод имен архивируемых файлов.
Странно. tee должен их дублировать в stderr.

Voral писал(а):
31.03.2010 20:10
Если файлов много будет для архивирования, то можно напороться на "переполнение" командной строки?
xargs -n 1 будет вызывать команду для каждого аргумента отдельно. Если хочется оптимизации и команда поддерживает, то можно убрать «-n 1». Тогда xargs будет вызывать команду с максимально допустимым числом аргументов, переполнения не будет.
Спасибо сказали: