
$ sh резервное копирование-в-s3.sh
backup-to-s3.sh: 11: [: bkup_20151106_150532.zip: unexpected operator
backup-to-s3.sh: 11: [: bkup_20151106_150532.zip: unexpected operator
backup-to-s3.sh: 11: [: bkup_20151106_150532.zip: unexpected operator
backup-to-s3.sh: 11: [: bkup_20151106_150532.zip: unexpected operator
backup-to-s3.sh: 11: [: bkup_20151106_150532.zip: unexpected operator
backup-to-s3.sh: 11: [: bkup_20151106_150532.zip: unexpected operator
ubuntu@accretive-staging-32gb-ephemeral:~$ cat резервное копирование-в-s3.sh
#Script to move /home/ubuntu/backup folder to S3://auto-backup
#Author Ashish Karpe
cd /mnt/backup
filename="bkup_$(date +%Y%m%d_)"
/bin/ls -alF | awk '{ print $9 }' > /tmp/file
for i in $(cat /tmp/file); do
# echo $i;
# read a;
# echo $filename;
if [ $filename* = $i ]
then
echo "Copying " $i "to S3://auto-backup";
s3cmd put $i s3://auto-backup
fi
done
решение1
не используйте
for
для перебора строк файла, используйтеwhile IFS= read -r line; do ...; done < filename
вам вообще не нужно направлять
ls
вывод в файл,особеннос использованием-F
- используйте bash
[[ x == y ]]
для сравнения шаблонов, шаблон находится справа:
#!/bin/bash
cd /mnt/backup
prefix="bkup_$(date +%Y%m%d_)"
for file in * .*; do
[[ -f $file ]] || continue # skip things like directories and soft links
if [[ $file == $prefix* ]]; then
echo "Copying " $file "to S3://auto-backup";
s3cmd put $file s3://auto-backup
fi
done < /tmp/file
решение2
Даже если вы записываете вывод «ls» в файл и анализируете его, вы косвенно анализируете вывод «ls», что либо проблематично, либо является очень плохой идеей, либо НЕПРАВИЛЬНО!!!, в зависимости от того, кого вы спрашиваете.
Вотпочему не следует анализировать вывод 'ls'!
ВотИмена файлов и пути в Shell: как это сделать правильно!
Например, если в имени одного из файлов есть символ «-» (тире/дефис), который не экранирован (путем добавления к нему обратной косой черты ('\')), то он может быть интерпретирован как параметр.
Избежать разбора «ls» можно так же просто:
find . -maxdepth 1 -iname "*"
.
./dont_parse_ls.sh
./array.dat
./.bashrc
./BASH.Indirect.Reference.sh
./basharray.sh
./.forever
Что получается то же самое, что и
/bin/ls -alF | awk '{ print $9 }'
./
../
.bashrc
.forever/
BASH.Indirect.Reference.sh
array.dat
basharray.sh*
dont_parse_ls.sh
YMMV
решение3
В сценарии есть как минимум 2 основные проблемы. Ваша основная проблема — это фрагмент:
if [ $filename* =
С этим есть несколько проблем. Во-первых, в скриптах оболочки вы не можете "glob" шаблон соответствия. Ну, вы можете, но если fileglob даст более одного соответствия, вы получите оба, и в этом случае программа "[" (да, это программа) попытается оценить:
filename1 filename2 filename3 = $i
Это работает только в том случае, если fileglob расширяется ровно до одного имени файла, а гарантировать это можно редко. В вашем случае $filename расширяется по крайней мере до одного файла, но вы должны знать, что это не всегда так. Если "$file*" расширяется вообще ни до какого файла, вы можете (в зависимости от настройки shopt) получить пустую строку:
= $i
что приведет [
к сбою. Однако при правильном выборе магазина вы вместо этого получите:
backup-2014-whatever* = $i
С *
бытием частью сравнения.
Вторая фундаментальная проблема — использование параметра -F
в ls
. Это говорит ls о необходимости добавлять к имени файла один из нескольких символов в зависимости от того, является ли файл исполняемым, программной ссылкой и т. д.
NetScr1be в чем-то прав, но, послушайте, вам не обязательно следовать совету NetScr1be и никогда не использовать ls
... просто не используйте ls -l
. Вместо этого используйте , ls -1
который выведет только имена файлов в один столбец, без излишеств. (Для очень больших каталогов он отсортирует их, и это может быть проблемой, в этом случае есть опция без сортировки; или используйте find.)
Для большей безопасности переменные следует заключать в двойные кавычки, а перед левой и правой частью следует ставить фиктивный символ, чтобы не допустить сбоя при использовании странных имен файлов, начинающихся с -
.
Я бы воспользовался советом Гленна, в большей или меньшей степени, и сделал бы это следующим образом:
command ls -1 | while read file; do
if [ x"$file" = x"$filename" ]]; then
echo Do Work Here
fi
done
Вот как ябысделать это, но Гленн любезно сообщил мне, что мне действительно следует это сделатьегоспособ:
for file in *; do
if [[ $file == $filename ]]; then ...
решение4
Этот скрипт делает все. Почему бы не сделать это? Оболочка выберет нужные файлы за вас, поэтому нет необходимости вызывать ls
:
#!/bin/sh
for file in /mnt/backup/bkup_$(date +%Y%m%d)_*
do
s3cmd put "$file" s3://auto-backup
done
- Единственная внешняя команда —
s3cmd
. - Никаких
if
заявлений. - Единственная точка принятия решения — это
for
петля. - Легко читается.