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"
Ответ 3
BASH FAQ # 50: "Я пытаюсь поместить команду в переменную, но сложные случаи всегда терпят неудачу!"
Ответ 4
Я согласен с Гордоном
В этом случае вам не нужно eval (вы не формируете имя переменной из переменных или иначе не выполняете выражение на лету)
И вы хотите сделать двойную котировку всех переменных referensces, у которых есть пробелы, которые вы хотели бы сохранить
Но другой хорошей привычкой является всегда ссылаться на переменные с помощью {}...
"${CURRENT_DIR}"
вместо
$CURRENT_DIR
Это устраняет любую неоднозначность имени
Ответ 5
Я знаю, вероятно, ypu уже использовал его, но как насчет одиночных кавычек? (этот тип '')?
Ответ 6
Вам нужно освободить место в CURRENT_DIR="/path/with\ spaces/backup"
, если это не сработает, тогда установите двойную обратную косую черту CURRENT_DIR="/path/with\\ spaces/backup"