Bash проблема с eval, переменными и кавычками

Я читал о котировках в bash здесь и везде, но я не получил помощи в решении этой проблемы.

Дело в том, что у меня немного script для выполнения резервных копий в цикле.

Если я не использую eval, то у меня возникают проблемы с переменной $OPTIONS в rsync.

Но если я использую eval, тогда проблема переходит к переменной $CURRENT_DIR...

rsync возвращает следующее сообщение: "Неожиданный локальный arg:/path/with '

Я пробовал каждый путь цитирования переменной $CURRENT_DIR

CURRENT_DIR="/path/with spaces/backup"
DIR="dir_by_project"
f=":/home/project_in_server"
OPTIONS="-avr --exclude 'public_html/cms/cache/**' --exclude 'public_html/cms/components/libraries/cmslib/cache/**' --delete"
eval rsync --delete-excluded -i $OPTIONS  [email protected]$f $CURRENT_DIR/xxx/$DIR/files

Есть ли способ, которым я могу использовать переменную $CURRENT_DIR без проблем, вызванных пробелами?

Ответ 1

eval rsync --delete-excluded -i $OPTIONS  [email protected]$f "\"$CURRENT_DIR/xxx/$DIR/files\""

command "some thing" выполняет команду с одним аргументом some thing. Кавычки обрабатываются оболочкой, а аргументы настраиваются как массив при выполнении команды. Команда увидит аргумент как нечто без кавычек.

Команда eval обрабатывает свои аргументы более или менее, как если бы они были введены в оболочку. Итак, если вы eval command "some thing", bash выполняет eval с двумя аргументами: command и some thing (опять же кавычки едят, а bash устанавливает массив аргументов). Таким образом, eval действует так, как если бы вы набрали command some thing в оболочке, чего вы не хотите.

То, что я делал, просто заключалось в том, чтобы избежать кавычек, чтобы bash проходил буквально "кое-что", включая кавычки для eval. eval действует так, как будто вы набрали command "some thing".

Внешние кавычки в моей команде строго не нужны, они просто привычка. Вы также можете использовать:

eval rsync --delete-excluded -i $OPTIONS  [email protected]$f \"$CURRENT_DIR/xxx/$DIR/files\"

Ответ 2

Использование eval опасно и его следует избегать, когда это возможно. В этом случае основной проблемой является то, что вы пытаетесь определить OPTIONS как содержащие несколько слов, а переменные bash не справляются с этим очень хорошо. Существует решение: поместить OPTIONS в массив вместо простой переменной (и использовать двойные кавычки во всех ссылках на переменные, чтобы пробелы не обрабатывались как разделители слов).

CURRENT_DIR="/path/with spaces/backup"
DIR="dir_by_project"
f=":/home/project_in_server"
OPTIONS=(-avr --exclude 'public_html/cms/cache/**' --exclude 'public_html/cms/components/libraries/cmslib/cache/**' --delete)
rsync --delete-excluded -i "${OPTIONS[@]}"  "[email protected]$f" "$CURRENT_DIR/xxx/$DIR/files"

Ответ 4

Я согласен с Гордоном

В этом случае вам не нужно eval (вы не формируете имя переменной из переменных или иначе не выполняете выражение на лету)

И вы хотите сделать двойную котировку всех переменных referensces, у которых есть пробелы, которые вы хотели бы сохранить

Но другой хорошей привычкой является всегда ссылаться на переменные с помощью {}...

  "${CURRENT_DIR}" 

вместо

  $CURRENT_DIR

Это устраняет любую неоднозначность имени

Ответ 5

Я знаю, вероятно, ypu уже использовал его, но как насчет одиночных кавычек? (этот тип '')?

Ответ 6

Вам нужно освободить место в CURRENT_DIR="/path/with\ spaces/backup", если это не сработает, тогда установите двойную обратную косую черту CURRENT_DIR="/path/with\\ spaces/backup"