Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Программирование в *nix (http://forum.oszone.net/forumdisplay.php?f=35)
-   -   SH скрипт копирования каталога (http://forum.oszone.net/showthread.php?t=245534)

ktotut 26-10-2012 17:24 2012761

SH скрипт копирования каталога
 
Добрый день!

Прошу помочь, пишу скрипт копирования целевой папки (внутри папки вложенная структура папок и файлов) в каталоги, список которых перечислен в текстовом файле (каждая строчка - новый каталог с указание пути относительно корня). Однако выполнение скрипта ни к чему не приводит..Помогите пожалуйста.


Пример содержимого текстового файла:
/home/centrin/domains/sites.ru/public_html/new/
/home/centrin/domains/home.ru/public_html/

Вот sh скрипт:
#!/bin/sh

if [ $# -ne 2 ]
then
echo "Параметры вызова: ([директория], [файл с адресами])"
exit
fi

PATHS_FILE=$2
TARGET_DIR=$1

if !([ -d $TARGET_DIR ])
then
echo "Заданная директория не найдена"
exit
fi

if !([ -f $PATHS_FILE ])
then
echo "Файл с адресами не найден"
exit
fi

while read LINE; do
if !([ -d $LINE ])
then
mkdir $LINE
fi

echo "$TARGET_DIR/* to $LINE"
cp -R $TARGET_DIR/* $path
done < $PATHS_FILE

echo "Done."

Kent 26-10-2012 21:54 2012948

Цитата:

Цитата ktotut
cp -R $TARGET_DIR/* $path »

А где определена переменная 'path'?

Цитата:

Цитата ktotut
if !([ -d $TARGET_DIR ]) »

На мой взгляд, круглые скобки не нужны.

AMDBulldozer 27-10-2012 19:13 2013352

ktotut, прошу прощения, но тут у Вас ошибка синтаксиса. Вместо
Цитата:

Цитата ktotut
f !([ -d $LINE ]) »

должно быть "if [ ! -d $LINE ]".
И еще, если позволите, два вопроса:
1. Учитываете ли Вы, что команда cp -R будет копировать далеко не все файлы? К примеру, не будут копироваться скрытые.
Я бы, на Вашем месте воспользовался бы либо командой rsync (rsync -a -H -A -X --devices --specials -c -v --delete "$TARGET_DIR"/ "$LINE"), либо tar ( cd "$TARGET_DIR"; tar cf - . | (cd "$LINE" && tar xBf -).
2. Сценарий не будет работать правильно, если директория или имя файла содержат спецсимволы. К примеру, пробел. Решить эту проблему можно правильным использованием кавычек и установкой IFS в $"\n".
Правда, файлы с символом перевода строки в имени всё равно не будут правильно обрабатываться, но, согласитесь, такие файлы встречаются редко (могу предложить вариант который будет правильно обрабатывать все файлы с корректными именами, даже содержащие переводы строки в имени, но, честно говоря, не вижу смысла - это не более, чем бесполезное упражнение в использовании команд оболочки, к тому же, его работоспособность далеко не очевидна с первого взгляда).

ktotut 27-10-2012 20:12 2013378

Вложений: 1
К сожалению видимо я много чего не учитываю, однако пока ничего не помогает...
прикладываю скрин с консоли.

сейчас текст скрипта выглядит так:
#!/bin/sh

if [ $# -ne 2 ]
then
echo "Параметры вызова: ([директория], [файл с адресами])"
exit
fi

PATHS_FILE=$2
TARGET_DIR=$1

if !([ -d $TARGET_DIR ])
then
echo "no directory"
exit
fi

if !([ -f $PATHS_FILE ])
then
echo "no file"
exit
fi

while read LINE;
do
if ([ ! -d $LINE ])
then
mkdir $LINE
fi
echo "$TARGET_DIR/* to $LINE"

echo $TARGET_DIR
echo $path

cp -R $TARGET_DIR/* $path
rsync -a -H -A -X --devices --specials -c -v --delete "$TARGET_DIR"/ "$LINE"

done < $PATHS_FILE

echo "Done."

AMDBulldozer 27-10-2012 20:36 2013385

ktotut, запустите, пожалуйста Ваш сценарий командой:
Код:

bash -x script.sh administator site.txt &> script.log
и добавьте script.log в качестве приложения к Вашему следующему сообщению.

Покажите, если не сложно, результат выполнения "ls -l `which sh`"

Я бы всё-таки рекомендовал Вам заменить в первой строчке #!/bin/sh на #!/bin/bash, сделать файл исполняемым (chmod a+x script.sh) и запускать его непосредственно, а не в виде параметра оболочки - это же неудобно.

P.S. Строчки
Цитата:

Цитата ktotut
if !([ -d $TARGET_DIR ]) »

и
Цитата:

Цитата ktotut
if !([ -f $PATHS_FILE ]) »

надо заменить на "if [ ! -d $TARGET_DIR ]" и if [ ! -f $PATHS_FILE ] соответственно. В Вашем случае восклицательный знак является не логическим оператором отрицания, а ссылкой на историю команд bash (если Ваш "sh" действительно ссылка на /bin/bash, а не на какой-нибудь ash или busybox).

Kent 27-10-2012 21:12 2013410

Цитата:

Цитата AMDBulldozer
Я бы всё-таки рекомендовал Вам заменить в первой строчке #!/bin/sh на #!/bin/bash »

Не видно ничего bash-специфичного, не имеет смысла.

Цитата:

Цитата AMDBulldozer
должно быть "if [ ! -d $LINE ]" »

Именно так.

Цитата:

Цитата AMDBulldozer
Учитываете ли Вы, что команда cp -R будет копировать далеко не все файлы? К примеру, не будут копироваться скрытые »

Позвольте не согласиться. Скрытые файлы копируются.

AMDBulldozer 27-10-2012 22:16 2013455

Цитата:

Цитата Kent
Позвольте не согласиться. Скрытые файлы копируются. »

Вы возможно не обратили внимание, что команда копирования у автора записана в форме
Цитата:

Цитата ktotut
cp -R $TARGET_DIR/* $path »

а это значит, что подстановка образца (wildcard) "звездочка" будет осуществляться оболочкой. То есть команда cp будет развернута в "cp dir/file1 dir/file2 dir/file3 ... path". При этом файлов начинающихся с точки в результирующей строке не будет, поскольку они не подпадают под шаблон "*".
Понятно, что автору проще было вообще не ставить последнюю звездочку, а ограничиться указанием директории.

AMDBulldozer 27-10-2012 22:34 2013460

Цитата:

Цитата Kent
Не видно ничего bash-специфичного, не имеет смысла. »

Тут вопрос в том, что /bin/sh у автора скорее всего символьная ссылка. Причем мы не знаем абсолютно ничего о системе автора и, стало быть, не можем делать предположения о том, какая оболочка там используется в действительности.
Поэтому, даже из соображений портируемости сценария, я всегда предпочитаю указывать реальную оболочку.
На любой настольной Linux-системе bash всегда будет установлен по умолчанию и его явное указание проблем создать не может.
А если, к примеру, сценарий используется на какой-либо встроенной системе, это позволяет сразу выявить причину ошибки, без необходимости долго копаться, прежде чем будет установлено, что оператор "[" не был включен в данную версию busybox.
Кроме того, это позволяет спокойно дорабатывать сценарий, включая в него специфичные для указанной оболочки возможности, не опасаясь того, что на другой машине вместо bash'а будет вызван dash (достаточно распространенная ситуация) и использованный в какой-то момент вместо "[" оператор "[[" будет интерпретирован как ошибка.

Kent 27-10-2012 23:53 2013509

Цитата:

Цитата AMDBulldozer
подстановка образца (wildcard) "звездочка" будет осуществляться оболочкой »

Вероятно, вы правы. В zsh у меня это работает.

Код:

kent@lazy /tmp % ls -aR copy*
copy-test:
.  ..  .cptest1  .cptest2

copy-test2:
.  ..
kent@lazy /tmp % cp -R copy-test/* copy-test2
kent@lazy /tmp % ls -aR copy*               
copy-test:
.  ..  .cptest1  .cptest2

copy-test2:
.  ..  .cptest1  .cptest2
kent@lazy /tmp % exec bash
kent@lazy:/tmp> ls -aR copy*
copy-test:
.  ..  .cptest1  .cptest2

copy-test2:
.  ..
kent@lazy:/tmp> cp -R copy-test/* copy-test2
cp: не удалось выполнить stat для «copy-test/*»: Нет такого файла или каталога


AMDBulldozer 28-10-2012 01:24 2013543

Цитата:

Цитата Kent
В zsh у меня это работает. »

Очень интересно. У меня не работает. zsh 4.3.17 Я считаю, что и не должен. На досуге попробую разобраться, как Вам удалось заставить его копировать скрытые файлы.

ktotut 28-10-2012 08:34 2013595

Вложений: 2
Всем добрый день!

Спасибо за активное участие в вопросе.
Система у меня Linux version 2.6.32-5-amd64 (Debian 2.6.32-46)
Прикладываю к сообщению log и скрипт (с внесенными изменениями)
и вот еще результат команды:
root@km35525:/home/centrin/domains/eduoren.ru/public_html# ls -l `which sh`
lrwxrwxrwx 1 root root 4 Apr 11 2012 /bin/sh -> bash

Kent 28-10-2012 11:36 2013639

Цитата:

Цитата AMDBulldozer
У меня не работает. zsh 4.3.17 »

zsh 5.0.0

AMDBulldozer 28-10-2012 15:33 2013720

ktotut, у Вас в текущем каталоге отсутствует директория "administrator". Поэтому выполнение сценария и прерывается с выдачей Вашего же сообщения об отсутствии дректории. Думаю, Вы это и сами заметили.
Рекомендация: вводите абсолютный путь директории.


P.S. Кстати, почему она называется "TARGET"? Скорее уж "SOURCE". Хотя на работу сценария это, ясен корень, никак не влияет. :wink:

AMDBulldozer 28-10-2012 15:50 2013730

Теперь по поводу Вашего сценария. Вы всё-аки не до конца внесли те правки, о которых я Вам говорил.

Оператору "if" не нужны круглые скобки. Это не язык "С". Конечно, во многих случаях они не мешают, но раз уж мы с Вами начали учиться писать сценарии, давайте сразу осваивать хороший стиль программирования. :wink:

Поэтому, убираем скобки в "if ([ ! -d $TARGET_DIR ])". Получается "if [ ! -d $TARGET_DIR ]".
Выражение "if !([ ! -f $PATHS_FILE ])" ошибочно в принципе, поскольку содержит ссылку на историю команд (в сценарии она недоступна).
Вполне вероятно, что эта команда может быть выполнена в сценарии (именно благодаря недоступности истории команд). Честно признаться, никогда не проверял. Но она совершенно точно не может быть исполнена в интерактивном режиме.
Так что заменяем Ваш вариант на простой и понятный "if [ ! -f $PATHS_FILE ]".

ktotut 28-10-2012 16:22 2013750

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

AMDBulldozer 28-10-2012 16:36 2013754

ktotut, опубликуйте, пожалуйста, содержимое файла site.txt.
Как видите, попытка чтения из этого файла завершается неудачно и сценарий сразу выходит из цикла while.

ktotut 28-10-2012 17:27 2013778

Вложений: 1
вот содержание файла site.txt

AMDBulldozer 28-10-2012 18:06 2013809

ktotut, у Вас файл site.txt не завершается переводом строки. Отсюда и ошибка - прчесть строку из файла нельзя, поскольку он содержит 0 строк (если не верите, можете проверить командой wc -l site.txt).
Кстати, заодно советовал бы добавить в команду mkdir опцию "-p". На всякий случай.

ktotut 28-10-2012 19:17 2013865

Вложений: 3
Да, я тоже думал на это - увы нет..вот скрин и файлы.

AMDBulldozer 28-10-2012 19:33 2013880

ktotut, тогда выкладывайте очередной log.txt! :wink:

Предположение №1: rsync у Вас не установлен, а команда cp не проходит потому, что, несмотря на то, что Вам еще в самом первом сообщении рекомендовали это сделать (не я), Вы забыли заменить "$path" на "$LINE".
Ведь переменная path у Вас нигде не определена, верно?

ktotut 28-10-2012 19:46 2013889

Вложений: 1
Забыл лог прикрепить. )

AMDBulldozer 28-10-2012 19:50 2013891

ktotut, что и требовалось доказать.
Посмотрите этот файл и сами всё поймете. Или прочитайте моё предыдущее сообщение.
ИЛИ установите rsync, ИЛИ замените везде $path на $LINE.

ktotut 28-10-2012 19:52 2013893

Вложений: 1
Всё заработало...заменить $path на $LINE

Прикладываю на всякий случай конечный вариант скрипта.

СПАСИБО ЗА ПОМОЩЬ!

AMDBulldozer 28-10-2012 19:55 2013897

Цитата:

Цитата ktotut
Прикладываю на всякий случай конечный вариант скрипта. »

а в команде "echo" заменять $path на $LINE не стали? Она, конечно, чисто информационная и ни на что не влияет...

ktotut 28-10-2012 20:50 2013923

не заметил просто )


Время: 04:22.

Время: 04:22.
© OSzone.net 2001-