PDA

Показать полную графическую версию : SH скрипт копирования каталога


Страниц : [1] 2

ktotut
26-10-2012, 17:24
Добрый день!

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


Пример содержимого текстового файла:
/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
cp -R $TARGET_DIR/* $path »
А где определена переменная 'path'?

if !([ -d $TARGET_DIR ]) »
На мой взгляд, круглые скобки не нужны.

AMDBulldozer
27-10-2012, 19:13
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
К сожалению видимо я много чего не учитываю, однако пока ничего не помогает...
прикладываю скрин с консоли.

сейчас текст скрипта выглядит так:
#!/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
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. Строчки if !([ -d $TARGET_DIR ]) » и
if !([ -f $PATHS_FILE ]) »

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

Kent
27-10-2012, 21:12
Я бы всё-таки рекомендовал Вам заменить в первой строчке #!/bin/sh на #!/bin/bash »
Не видно ничего bash-специфичного, не имеет смысла.

должно быть "if [ ! -d $LINE ]" »
Именно так.

Учитываете ли Вы, что команда cp -R будет копировать далеко не все файлы? К примеру, не будут копироваться скрытые »
Позвольте не согласиться. Скрытые файлы копируются.

AMDBulldozer
27-10-2012, 22:16
Позвольте не согласиться. Скрытые файлы копируются. »

Вы возможно не обратили внимание, что команда копирования у автора записана в форме cp -R $TARGET_DIR/* $path »

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

AMDBulldozer
27-10-2012, 22:34
Не видно ничего bash-специфичного, не имеет смысла. »

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

Kent
27-10-2012, 23:53
подстановка образца (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
В zsh у меня это работает. »

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

ktotut
28-10-2012, 08:34
Всем добрый день!

Спасибо за активное участие в вопросе.
Система у меня 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
У меня не работает. zsh 4.3.17 »
zsh 5.0.0

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


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

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

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

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

ktotut
28-10-2012, 16:22
поправил. Директория находится на одном уровне со скриптом, просто допустил ошибку...
однако ничего не изменилось.
Прикладываю файлы.

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

ktotut
28-10-2012, 17:27
вот содержание файла site.txt

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

ktotut
28-10-2012, 19:17
Да, я тоже думал на это - увы нет..вот скрин и файлы.

AMDBulldozer
28-10-2012, 19:33
ktotut, тогда выкладывайте очередной log.txt! :wink:

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




© OSzone.net 2001-2012