Різниця між одинарними та подвійними цитатами в Bash


Відповіді:


578

Одиночні котирування нічого не інтерполюють, але подвійні лапки будуть. Наприклад: змінні, зворотні посилання, певні \виходи тощо.

Приклад:

$ echo "$(echo "upg")"
upg
$ echo '$(echo "upg")'
$(echo "upg")

У посібнику Bash сказано:

3.1.2.2 Одиночні цитати

Замикання символів в одиничних лапках ( ') зберігає буквальне значення кожного символу в лапках. Одиночна цитата може не виникати між окремими цитатами, навіть коли передує зворотна косою рисою.

3.1.2.3 Подвійні цитати

Огороджувальні символи в подвійних лапках ( ") зберігає буквальне значення всіх символів в лапках, за винятком $, `, \та, коли розкриття історії включено, !. Символи $та `зберігають своє особливе значення у подвійних лапках (див. Розширення оболонки ). Зворотний слеш зберігає свій особливий сенс тільки тоді , коли слід один з наступних символів: $, `, ",\або новий рядок У межах подвійних лапок знімаються нахили, які супроводжуються одним із цих символів. Підсумки, що передують символам без особливого значення, залишаються незмінними. Подвійна котировка може бути наведена в подвійних лапках, попередньо додавши її до зворотної косої риски. Якщо це ввімкнено, розширення історії буде виконуватися, якщо не з’явиться !поява у подвійних лапки за допомогою зворотної косої риски. Нахил, який передує !, не знімається.

Спеціальні параметри *і @мають особливе значення у подвійних лапках (див. Розширення параметра оболонки ).


40
Для тих, хто не знає, що означає "інтерполяція": en.wikipedia.org/wiki/String_interpolation
Калонь Колоб

Що з приводу того, що ви використовуєте git_promptцей git, вони передбачають, що вони пропонують його використовувати таким чином PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ ', git prompt , відповідно до цього не повинно працювати. Чи є щось особливе у PS#змінних? або чому це працює, якщо це не робить інтерполяція.
ekiim

@ekiim Цей точний текст встановлюється (незмінним) у PS1. Спробуйте echo $PS1зрозуміти, що я маю на увазі. Але PS1він оцінюється перед тим, як відображатись (див. PROMPTINGРозділ на баш-сторінці). Щоб перевірити це, спробуйте PS1='$X'. У вас не буде запиту. Потім запустіть X=fooі раптом ваш запит стає "foo" ( PS1оцінювались, коли встановлено замість відображуваного, у вас все одно не буде запиту).
Адам

262

Загальноприйнятий відповідь великий. Я складаю таблицю, яка допомагає швидко розібратися в темі. Пояснення включає просту змінну a, а також індексований масив arr.

Якщо ми встановимо

a=apple      # a simple variable
arr=(apple)  # an indexed array with a single element

і тоді echoвираз у другому стовпці, ми отримаємо результат / поведінку, показані в третьому стовпці. Четверта колонка пояснює поведінку.

 # | Expression  | Result      | Comments
---+-------------+-------------+--------------------------------------------------------------------
 1 | "$a"        | apple       | variables are expanded inside ""
 2 | '$a'        | $a          | variables are not expanded inside ''
 3 | "'$a'"      | 'apple'     | '' has no special meaning inside ""
 4 | '"$a"'      | "$a"        | "" is treated literally inside ''
 5 | '\''        | **invalid** | can not escape a ' within ''; use "'" or $'\'' (ANSI-C quoting)
 6 | "red$arocks"| red         | $arocks does not expand $a; use ${a}rocks to preserve $a
 7 | "redapple$" | redapple$   | $ followed by no variable name evaluates to $
 8 | '\"'        | \"          | \ has no special meaning inside ''
 9 | "\'"        | \'          | \' is interpreted inside "" but has no significance for '
10 | "\""        | "           | \" is interpreted inside ""
11 | "*"         | *           | glob does not work inside "" or ''
12 | "\t\n"      | \t\n        | \t and \n have no special meaning inside "" or ''; use ANSI-C quoting
13 | "`echo hi`" | hi          | `` and $() are evaluated inside ""
14 | '`echo hi`' | `echo hi`   | `` and $() are not evaluated inside ''
15 | '${arr[0]}' | ${arr[0]}   | array access not possible inside ''
16 | "${arr[0]}" | apple       | array access works inside ""
17 | $'$a\''     | $a'         | single quotes can be escaped inside ANSI-C quoting
18 | "$'\t'"     | $'\t'       | ANSI-C quoting is not interpreted inside ""
19 | '!cmd'      | !cmd        | history expansion character '!' is ignored inside ''
20 | "!cmd"      | cmd args    | expands to the most recent command matching "cmd"
21 | $'!cmd'     | !cmd        | history expansion character '!' is ignored inside ANSI-C quotes
---+-------------+-------------+--------------------------------------------------------------------

Дивись також:


1
Зрештою, відповідь говорить про The special parameters * and @ have special meaning when in double quotesте, як приходять "*"результати *?
anddero

2
@ Karl-AnderoMere, оскільки вони взагалі не розгорнуті як параметри. "$@"і "$*"є розширенням параметрів. "@"і "*"не є.
Чарльз Даффі

@CharlesDuffy Спасибі, зараз має сенс!
anddero

3
Номер 9 echo "\'", повертає мене \'.
MaxGyver

@MaxGyver: дякую за вказівку. Я оновив відповідь.
codeforester

233

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

Наприклад, це

#!/bin/sh
MYVAR=sometext
echo "double quotes gives you $MYVAR"
echo 'single quotes gives you $MYVAR'

дасть це:

double quotes gives you sometext
single quotes gives you $MYVAR

11

Інші пояснили дуже добре і просто хочуть навести прості приклади.

Окремі лапки можуть використовуватися навколо тексту, щоб запобігти інтерпретації оболонки будь-яких спеціальних символів. Знаки долара, пробіли, амперсанди, зірочки та інші спеціальні символи ігноруються, якщо вони укладені в межах однієї лапки.

$ echo 'All sorts of things are ignored in single quotes, like $ & * ; |.' 

Це дасть це:

All sorts of things are ignored in single quotes, like $ & * ; |.

Єдине, що не може бути поставлено в межах однієї лапки, - це єдина цитата.

Подвійні котирування діють аналогічно одиночним котируванням, за винятком того, що подвійні лапки все ще дозволяють оболонці інтерпретувати знаки долара, зворотні котирування та зворотні риски. Вже відомо, що нахили на зворотному боці заважають інтерпретувати єдиний спеціальний символ. Це може бути корисно в подвійних лапках, якщо знак долара потрібно використовувати як текст замість змінної. Це також дозволяє уникнути подвійних лапок, тому вони не трактуються як кінець рядка, що цитується.

$ echo "Here's how we can use single ' and double \" quotes within double quotes"

Це дасть це:

Here's how we can use single ' and double " quotes within double quotes

Можна також помітити, що апостроф, який інакше трактуватиметься як початок цитованого рядка, ігнорується в подвійних лапках. Однак змінні інтерпретуються та замінюються їх значеннями в подвійних лапках.

$ echo "The current Oracle SID is $ORACLE_SID"

Це дасть це:

The current Oracle SID is test

Зворотні котирування зовсім не схожі на одиничні чи подвійні. Замість того, щоб використовувати їх для запобігання інтерпретації спеціальних символів, зворотні лапки фактично змушують виконувати команди, які вони додають. Після виконання вкладених команд їх вихід замінюється замість зворотних лапок у вихідному рядку. Це буде зрозуміліше на прикладі.

$ today=`date '+%A, %B %d, %Y'`
$ echo $today 

Це дасть це:

Monday, September 28, 2015 

3

Існує чітка відмінність між використанням ' 'та " ".

Коли ' 'навколо нічого не використовується, "трансформація чи переклад" не робиться. Він друкується як є.

З тим " ", що б воно не оточувало, "перекладається чи перетворюється" на свою цінність.

Під перекладом / перетворенням я маю на увазі наступне: Все, що знаходиться в рамках однієї лапки, не буде "переведене" на їх значення. Вони будуть прийняті, як вони є всередині котирувань. Приклад:, a=23тоді echo '$a'буде вироблятися $aна стандартному виході. Тоді як echo "$a"буде вироблятися 23на стандартній продукції.


1
Що ви маєте на увазі під «перекладом» чи «трансформацією»?
Ніко Хааз

Ця відповідь є досить заплутаною, і вона нічого не додає на додаток до існуючих хороших відповідей.
codeforester

2
На мою думку, це була коротка стисла відповідь, не надто багатословно, що мені було легко зрозуміти. Коли говорять переклад / перетворення, вони означають, що подвійні лапки розширять змінну, де окремі лапки не розширять змінну.
B_e_n_n_y_

1
Так, це найкраща відповідь. Це має бути прийнятою відповіддю.
Джеймі Кірбі

3

Оскільки це фактична відповідь при роботі з цитатами bash, я додам ще один момент, пропущений у відповідях вище, під час роботи з арифметичними операторами в оболонці.

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

Важливо розуміти, що арифметичний вираз, який використовується для, letзазнає розбиття слів, розширення імені шляху, як і будь-які інші команди оболонки. Отже, належне цитування та втеча потрібно робити.

Дивіться цей приклад під час використання let

let 'foo = 2 + 1'
echo $foo
3

Використання одиничних лапок тут абсолютно чудово, оскільки тут немає потреби в змінних розширеннях, розглянемо випадок

bar=1
let 'foo = $bar + 1'

буде невдало, оскільки $barпід єдиними котируваннями не буде розширюватися і його потрібно подвоїти

let 'foo = '"$bar"' + 1'

Це має бути однією з причин, що $((..))завжди слід враховувати над використанням let. Оскільки всередині нього вміст не підлягає поділу слів. Попередній приклад letможна просто записати як

(( bar=1, foo = bar + 1 ))

Завжди пам’ятайте, щоб використовувати $((..))без одиничних лапок

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

printf '%d\n' '$((1+1))'
-bash: printf: $((1+1)): invalid number
printf '%d\n' $((1+1))
2
printf '%d\n' "$((1+1))"
2

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

curl http://myurl.com --data-binary '{"requestCounter":'"$((reqcnt++))"'}'

Зауважте використання внутрішніх вкладених подвійних лапок, без яких буквальна рядок $((reqcnt++))передається в requestCounterполе.


2
Чарльз Даффі робить хороший випадок тут для подвійний процитувати , $((...))як добре. Це може бути "трохи" параноїком, і навряд чи це буде, IFS=0наприклад, але це, безумовно, неможливо :)
PesaThe

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