Зв'язування рядків 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.