Разница между одинарными и двойными кавычками в Bash


Ответы:


580

Одинарные кавычки не будут ничего интерполировать, но двойные кавычки будут. Например: переменные, обратные метки, некоторые \экранированные символы и т. Д.

Пример:

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

В руководстве по Bash сказано следующее:

3.1.2.2 Одиночные кавычки

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

3.1.2.3 Двойные кавычки

Ограждающие символы в двойных кавычках ( ") сохраняет буквальное значение всех символов в кавычках, за исключением $, `, \и, когда раскрывание истории включено, !. Символы $и `сохраняют свое особое значение в двойных кавычках (см. Расширения оболочки ). Обратный слэш сохраняет свой особый смысл только тогда , когда следует один из следующих символов: $, `, ",\или перевод строки. В двойных кавычках удаляются обратные слэши, за которыми следует один из этих символов. Обратная косая черта предшествующих символов без специального значения остается неизменной. Двойная кавычка может быть заключена в двойные кавычки, если им предшествует обратный слеш. Если включено, расширение истории будет выполняться, если !в двойных кавычках не будет отображаться обратный слеш. Обратная косая черта, предшествующая символу !, не удаляется.

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


41
Для тех, кто не знает, что означает «интерполировать»: en.wikipedia.org/wiki/String_interpolation
Каньон Колоб

1
Что касается того, что когда вы используете git_promptgit, который они предлагают, они предлагают использовать его следующим образом PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ ', git prompt , в соответствии с этим не должно работать. Есть ли что-то особенное в PS#переменных? или почему это работает, если он не выполняет интерполяцию.
Экиим

1
@ekiim Точный текст установлен (без изменений) в PS1. Попробуйте echo $PS1понять, что я имею в виду. Но PS1оценивается перед отображением (см. PROMPTINGРаздел на странице руководства bash). Чтобы проверить это, попробуйте PS1='$X'. У вас не будет подсказки. Затем запустите, X=fooи внезапно ваш запрос будет «foo» ( PS1был оценен, когда установлен вместо отображения, у вас все равно не будет запроса).
Адам Баткин

263

Общепринятый ответ велик. Я делаю таблицу, которая помогает в быстром понимании темы. Объяснение включает в себя как простую переменную, 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так как получится "*"результат *?
Андро

2
@ Karl-AnderoMere, потому что в этом случае они вообще не раскрываются как параметры. "$@"и "$*"расширения параметров. "@"и "*"нет.
Чарльз Даффи

@CharlesDuffy Спасибо, теперь это имеет смысл!
Андро

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

Существует также устаревший $[[...]]синтаксис, но, возможно, вы были правы, забыв об этом.
tripleee
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.