LINUX.ORG.RU

Экранирование и кавычки

 


0

2

Пишу скрипт для бэкапа с помощью rsync, необходимо включать правила для фильтрации. И вот тут поджидает фейл. Если просто ввести в консоли

rsync -av --delete --filter="merge some.filter" source/ destination/

то всё нормально. Если же написать вот такой bash-скрипт, который, казалось бы, делает то же самое, то rsync оказывается недоволен:

#!/bin/bash

RSYNC_PARAMS="-avh --delete"
RSYNC_FILTERS='--filter="merge some.filter"'

echo rsync $RSYNC_PARAMS $RSYNC_FILTERS source/ destination/
rsync $RSYNC_PARAMS $RSYNC_FILTERS source/ destination/
yl3dy bash_test $ ls
destination  some.filter  source  test.sh
yl3dy bash_test $ ls source
7z_old_lappy.tar.bz2  backup.log  file1.tmp  image.tar.bz2  ref.sh
yl3dy bash_test $ cat some.filter
- *.tmp
yl3dy bash_test $ ./test.sh
rsync -avh --delete --filter="merge some.filter" source/ destination/
Unknown filter rule: `"merge'
rsync error: syntax or usage error (code 1) at exclude.c(904) [client=3.1.0]

Еще пробовал такие варианты для переменной RSYNC_FILTERS:

RSYNC_FILTERS="--filter='merge some.filter'"
RSYNC_FILTERS="--filter=\"merge some.filter\""

Как заставить bash передавать правильный аргумент?

UPD: пропустил знак = в первой команде.

★★★

Последнее исправление: lu4nik (всего исправлений: 1)

Если ты указываешь у аргумента --filter знак «=», он, видимо, воспринимает только то, что идёт до пробела. Попробуй в скрипте в переменной передать фильтр так же, как и в консоли, т.е. без знака равно.

shell-script ★★★★★
()

orig

rsync -av --delete --filter «merge some.filter» source/ destination/
--filter «merge some.filter»

in script

rsync -avh --delete --filter=«merge some.filter» source/ destination/
--filter=«merge some.filter»

Подвох вижу я.

fraxinum
()
Ответ на: комментарий от fraxinum

Да, это я не совсем то скопировал. Экспериментировал с = и без, в обоих случаях в скрипте не работает, а при ручном наборе работает.

lu4nik ★★★
() автор топика
Ответ на: комментарий от lu4nik

Есть опция '--filter' так и используйте её, зачем вы её запихали в переменную ?

RSYNC_FILTERS=\"merge some.filter\"
rsync -av --delete --filter=${RSYNC_FILTERS} source/ destination/

или

RSYNC_FILTERS="merge some.filter"
rsync -av --delete --filter="${RSYNC_FILTERS}" source/ destination/

kostik87 ★★★★★
()
Ответ на: комментарий от lu4nik

Почитав манчик, выяснил что тебе нужно:

RSYNC_PARAMS='-avh --delete'
RSYNC_FILTERS='--filter=merge some.filter'

rsync $RSYNC_PARAMS $RSYNC_FILTERS source/ destination/

Или в крайнем случае с костылём:

RSYNC_PARAMS='-avh --delete'
RSYNC_FILTERS='--filter=merge some.filter'

rsync $RSYNC_PARAMS "'$RSYNC_FILTERS'" source/ destination/

Суть в том, что оно не любит кавычки. А в случае шелла они преобразуются иначе.

Интересно, прав ли я, сейчас не удобно проверить самому.

fraxinum
()
Ответ на: комментарий от fraxinum

Увы, оба варианта не прокатывают. Вот что выдает первый:

yl3dy bash_test $ ./test.sh
rsync -avh --delete --filter merge some.filter source/ destination/
unexpected end of filter rule: merge
rsync error: syntax or usage error (code 1) at exclude.c(1013) [client=3.1.0]

Второй:

yl3dy bash_test $ ./test.sh
rsync -avh --delete --filter merge some.filter source/ destination/
sending incremental file list
rsync: link_stat "/tmp/bash_test/'--filter merge some.filter'" failed: No such file or directory (2)
./
7z_old_lappy.tar.bz2
backup.log
file1.tmp
image.tar.bz2
ref.sh

sent 15.29K bytes  received 114 bytes  30.81K bytes/sec
total size is 14.89K  speedup is 0.97
rsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1183) [sender=3.1.0]

Вроде бы не сфейлился, но пропустил file1.tmp, который был запрещен в some.filter.

lu4nik ★★★
() автор топика
Ответ на: комментарий от kostik87

В принципе, так можно сделать, но это не очень хорошо. Я свел весь скрипт к небольшому примеру, в оригинальном используются 2 filter-файла, и таскать по коду простыню типа --filter="merge rsync_filters/filter1" --filter="merge rsync_filters/filter2" неудобно.

Кроме того, интересно узнать причины такого поведения баша. Вроде как команды идентичны.

lu4nik ★★★
() автор топика
Ответ на: комментарий от lu4nik

Насколько понял, фишка втом, что rsync кавычки НЕ нужны, так что не следует их заталкивать в переменную. В таких случаях иногда проще с eval, хотя можно и без него обойтись.

Elyas ★★★★★
()
Ответ на: комментарий от lu4nik

Пришлось сесть за машину ~____~

lord@home-machine:~$ mkdir test
lord@home-machine:~$ cd test/
lord@home-machine:~/test$ mkdir 1 2
lord@home-machine:~/test$ touch ./1/{qwe.no,qwe.yes,rty.yes}
lord@home-machine:~/test$ lvim rs.sh
lord@home-machine:~/test$ chmod +x rs.sh
lord@home-machine:~/test$ lvim rule.filter
lord@home-machine:~/test$
lord@home-machine:~/test$ ./rs.sh 
sending incremental file list
./
qwe.yes
rty.yes

sent 156 bytes  received 53 bytes  418.00 bytes/sec
total size is 4  speedup is 0.02
lord@home-machine:~/test$
lord@home-machine:~/test$
lord@home-machine:~/test$ cat rs.sh 
#!/bin/bash

rule1='--filter=merge rule.filter'

rsync -av --delete "${rule1}" 1/ 2/
fraxinum
()
Ответ на: комментарий от Elyas

Можно тогда пример? Если в скрипте вообще убрать кавычки вокруг merge some.filter, то rsync просто будет недоволен, что правило merge незавершено (что логично).

lu4nik ★★★
() автор топика
Ответ на: комментарий от fraxinum

Этот вариант таки работает, большое спасибо. По закону Мэрфи, при переборе я его пропустил. Как я хотел изначально, не получается всё равно, т.к. на втором filter-файле он валится, но я просто прописал merge в первый.

Правда, интересно, почему исходный вариант не работал. Полистав ман баша, ничего подходящего не нашел.

lu4nik ★★★
() автор топика
Ответ на: комментарий от lu4nik

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

Elyas ★★★★★
()

"--filter=merge some.filter"

#!/bin/bash

RSYNC_PARAMS="-avh --delete"
RSYNC_FILTERS='"--filter=merge some.filter"'

echo rsync $RSYNC_PARAMS $RSYNC_FILTERS source/ destination/
rsync $RSYNC_PARAMS $RSYNC_FILTERS source/ destination/
Хоть и запоздало. Но никто такого варианта не предложил :D

nexfwall ★★★★
()
Последнее исправление: nexfwall (всего исправлений: 2)
Ответ на: комментарий от fraxinum

Как только ты делаешь program $VAR, bash автоматически разбивает на параметры содержимое $VAR по стандартным правилам баша(по whitespace). Для того и ковычки, чтобы это предотвратить

nexfwall ★★★★
()
Ответ на: комментарий от nexfwall

Мда, неявный баш такой неявный. Я уже забил на эту магию и сделал то же самое на питоне - модуль subprocess, благо, позволяет прямо явным списочком из строк передать параметры для rsync.

lu4nik ★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.