Показать полную графическую версию : 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."
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".
Правда, файлы с символом перевода строки в имени всё равно не будут правильно обрабатываться, но, согласитесь, такие файлы встречаются редко (могу предложить вариант который будет правильно обрабатывать все файлы с корректными именами, даже содержащие переводы строки в имени, но, честно говоря, не вижу смысла - это не более, чем бесполезное упражнение в использовании команд оболочки, к тому же, его работоспособность далеко не очевидна с первого взгляда).
К сожалению видимо я много чего не учитываю, однако пока ничего не помогает...
прикладываю скрин с консоли.
сейчас текст скрипта выглядит так:
#!/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).
Я бы всё-таки рекомендовал Вам заменить в первой строчке #!/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 (достаточно распространенная ситуация) и использованный в какой-то момент вместо "[" оператор "[[" будет интерпретирован как ошибка.
подстановка образца (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 Я считаю, что и не должен. На досуге попробую разобраться, как Вам удалось заставить его копировать скрытые файлы.
Всем добрый день!
Спасибо за активное участие в вопросе.
Система у меня 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
У меня не работает. 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 ]".
поправил. Директория находится на одном уровне со скриптом, просто допустил ошибку...
однако ничего не изменилось.
Прикладываю файлы.
AMDBulldozer
28-10-2012, 16:36
ktotut, опубликуйте, пожалуйста, содержимое файла site.txt.
Как видите, попытка чтения из этого файла завершается неудачно и сценарий сразу выходит из цикла while.
вот содержание файла site.txt
AMDBulldozer
28-10-2012, 18:06
ktotut, у Вас файл site.txt не завершается переводом строки. Отсюда и ошибка - прчесть строку из файла нельзя, поскольку он содержит 0 строк (если не верите, можете проверить командой wc -l site.txt).
Кстати, заодно советовал бы добавить в команду mkdir опцию "-p". На всякий случай.
Да, я тоже думал на это - увы нет..вот скрин и файлы.
AMDBulldozer
28-10-2012, 19:33
ktotut, тогда выкладывайте очередной log.txt! :wink:
Предположение №1: rsync у Вас не установлен, а команда cp не проходит потому, что, несмотря на то, что Вам еще в самом первом сообщении рекомендовали это сделать (не я), Вы забыли заменить "$path" на "$LINE".
Ведь переменная path у Вас нигде не определена, верно?
© OSzone.net 2001-2012
vBulletin v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.
Available in ZeroNet 1osznRoVratMCN3bFoFpR2pSV5c9z6sTC