Я повторил проблему и использовал set -x
чтобы увидеть, как на самом деле выглядят обе команды. Оказалось эта команда
rsync ${RSYNC_OPTIONS} ${SOURCEDIR} ${TARGET}
на самом деле эквивалентно этому
rsync -av --exclude '"done"' ${SOURCEDIR} ${TARGET}
Обратите внимание на кавычки в кавычках. Ваш образец не done
; это "done"
, как если бы каталог, который вы хотите исключить, содержал двойные кавычки в своем фактическом имени.
Чтобы почти это исправить, вы можете объявить переменную без этих кавычек:
RSYNC_OPTIONS='-av --exclude done' # poor fix, don't
rsync ${RSYNC_OPTIONS} "${SOURCEDIR}" "${TARGET}"
Но это будет иметь неприятные последствия, если шаблон содержит пробелы и т.д. Другой подход может быть с eval
:
RSYNC_OPTIONS='-av --exclude "name with double spaces"'
eval rsync "${RSYNC_OPTIONS}" '"${SOURCEDIR}" "${TARGET}"' # not recommended
eval
проанализирует строку во второй раз. Это очень трудно использовать правильно и безопасно. Я дважды заключаю в кавычки ${RSYNC_OPTIONS}
поэтому "name with double spaces"
не теряет двойных пробелов. Я заключил в кавычки "${SOURCEDIR}" "${TARGET}"
, поэтому эти переменные не раскрываются сразу (иначе их содержимое подвергнется расширению). Это сложно!
Кроме того, как насчет name "with' quotes
? Чтобы получить эту точную строку в качестве аргумента-опции для rsync --exclude
вам нужны неясные кавычки и экранирование в объявлении RSYNC_OPTIONS
. Есть больше причин, чтобы избежать eval
.
Реальным решением является использование массива в Bash. Примечание массивы не являются переносимыми.
RSYNC_OPTIONS=(-av --exclude 'name with spaces and $u(h')
rsync "${RSYNC_OPTIONS[@]}" "${SOURCEDIR}" "${TARGET}"
Я понимаю, почему вы не ${RSYNC_OPTIONS}
в своем первоначальном подходе. Вы должны были процитировать ${SOURCEDIR}
и (отдельно) ${TARGET}
. Приведенная выше команда правильно указывает каждую переменную.
Или, возможно, ${SOURCEDIR}
предназначался для указания нескольких источников? Это было бы причиной не заключать его в кавычки, но тогда это может привести к тем же проблемам, что и ${RSYNC_OPTIONS}
. В этом случае вам также следует обязательно использовать переменную массива.
Также учитывайте имена переменных в нижнем регистре.