Зв'язування рядків Bash, що використовується для складання списку параметрів


12

З огляду на цей шматок басу:

PARMS='-rvu'
PARMS+=" --delete --exclude='.git'"
echo $PARMS
rsync ${PARMS} . ${TARGET}

Відлуння показує рядок PARMS як очікувалося, помилка не відображається, але rsync мовчки діє так, як ніби опції, додані знаком + =, не існували. Однак це працює, як очікувалося:

PARMS='-rvu'
rsync ${PARMS} --delete --exclude='.git' . ${TARGET}

Я думаю, що я щось накрутив цитатами bash (завжди з ними були проблеми), але не зовсім впевнений, що і чому варіанти ігноруються, навіть незважаючи на те, що рядок, здається, побудований правильно.


1
echo "$PARMS"і rsync "${PARMS}"...
jasonwryan

Це працює для мене з bashверсією 4.2.25 без будь-яких змін.
Антон

Відповіді:


17

Існує різниця між:

PARMS+="... --exclude='.git'"

і

... --exclude='.git'

По-перше, одиничні лапки є всередині самих цитат, тому вони буквально присутні в заміненому тексті, поданому rsyncяк аргументи. rsyncотримує аргумент, значення якого --exclude='.git'. По-друге, одиничні лапки інтерпретуються оболонкою під час написання, оскільки вони не знаходяться всередині лапок, і вони rsyncможуть побачити --exclude=.git.

У цьому випадку вам не потрібні єдині лапки - .gitце ідеально дійсне слово оболонки самостійно, без спеціальних символів, тому ви можете використовувати його буквально в команді.

Хоча для цієї речі краще - це масив :

PARMS=(-rvu)
PARMS+=(--delete --exclude='.git')
rsync "${PARMS[@]}"

Це створює вашу команду як окремі слова, з будь-яким цитуванням, яке ви хочете інтерпретувати під час написання рядка масиву. "${PARMS[@]}"розгортається до кожного запису в масиві як окремий аргумент, навіть якщо сам аргумент має в ньому спеціальні символи чи пробіли, тож rsyncбачить те, що ви написали так, як ви це мали на увазі.


bashвиконували розбиття слів після того, як ${PARMS}було розширено. Тож єдина цитата була також інтерпретована оболонкою.
cuonglm

2
Спробуй це! Я зробив. Цитати залишаються, і якщо між ними були пробіли, вони все одно розділяються.
Майкл Гомер

@Gnouc: На сторінці Баш людини: «Цитата видалення: Після попередніх розширень, все котируються входження символів \ , 'і ". , Що ні є результатом однієї з вищевказаних розширень видаляються» "вище розширень" включає в себе Розширення параметра, яке виконує розширення ${PARMS}.
camh

Дякую. Тож я розумію, що в такому випадку пропуск одинарних лапок всередині подвійних буде спрацьовувати, але задля повноти - що робити, якщо мені потрібно процитувати деякі особливі символи, і я не хотів використовувати ваш останній підхід?
neuviemeporte

Якщо ваші спеціальні символи не входять до складу IFS(як правило, пробілів), цитувати їх вам не потрібно. Якщо вони є, то вам не пощастить, якщо ви щось не evalзламаєте разом - це взагалі дефіцит, і масиви - це правильний спосіб впоратися з цим.
Майкл Гомер

2

Окрім відповіді @Michael Homer , ви можете використовувати bash функцію eval :

PARMS='-rvu'
PARMS+=" --delete --exclude='.git'"
echo "$PARMS"
eval "rsync ${PARMS} . "'"${TARGET}"'

2
Можна, але не слід. Масиви були додані спеціально, щоб уникнути цього використання eval.
чепнер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.