Bash中单引号和双引号的区别

Posted

技术标签:

【中文标题】Bash中单引号和双引号的区别【英文标题】:Difference between single and double quotes in Bash 【发布时间】:2021-08-29 13:56:54 【问题描述】:

在 Bash 中,单引号 ('') 和双引号 ("") 有什么区别?

【问题讨论】:

另见(可能的跨站点重复):What is the difference between “…”, '…', $'…', and $“…” quotes?,来自 Unix & Linux Stack Exchange 标题是 Bash,但这确实适用于任何与 Bourne 兼容的 shell(经典 Bourne shell、POSIX shashdashksh 和 - 有一些注意事项- zsh)。 【参考方案1】:

单引号不会插入任何内容,但双引号会。例如:变量、反引号、某些\转义等。

例子:

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

Bash 手册是这样说的:

3.1.2.2 Single Quotes

将字符括在单引号 (') 中会保留引号内每个字符的字面值。单引号之间可能不会出现单引号,即使前面有反斜杠。

3.1.2.3 Double Quotes

将字符括在双引号 (") 中会保留引号内所有字符的字面值,$`\ 和启用历史扩展时,@987654334 除外@。字符$` 在双引号中保留其特殊含义(请参阅Shell Expansions)。反斜杠仅在后跟以下字符之一时才保留其特殊含义:$`"\ 或换行符。在双引号内,将删除后面跟有这些字符之一的反斜杠。没有特殊含义的字符前面的反斜杠保持不变。双引号可以用反斜杠在双引号中引用。如果启用,将执行历史扩展,除非出现在双引号中的 ! 使用反斜杠转义。 ! 前面的反斜杠不会被删除。

特殊参数*@ 在双引号中具有特殊含义(参见Shell Parameter Expansion)。

【讨论】:

对于任何不知道“插值”是什么意思的人:en.wikipedia.org/wiki/String_interpolation 当你使用 git 提供的git_prompt 时,他们建议像这样使用它PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ ',git prompt,根据这不应该工作。 PS# 变量有什么特别之处吗?或者如果它不进行插值,为什么它会起作用。 @ekiim 将确切的文本设置(未更改)到PS1。试试echo $PS1 看看我的意思。但是 PS1 在显示之前会被评估(参见 bash 手册页中的 PROMPTING 部分)。要对此进行测试,请尝试PS1='$X'。您将没有提示。然后运行X=foo,突然你的提示是“foo”(如果在 set 而不是 displayed 时评估了PS1,你仍然没有提示)。【参考方案2】:

accepted answer 很棒。我正在制作一个有助于快速理解该主题的表格。解释涉及到一个简单的变量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 $arocks 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 "" (backquotes are retained in actual output)
14 '`echo hi`' `echo hi` `` and $() are not evaluated inside '' (backquotes are retained in actual output)
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

另见:

ANSI-C quoting with $'' - GNU Bash Manual Locale translation with $"" - GNU Bash Manual A three-point formula for quotes

【讨论】:

接受的答案最后说The special parameters * and @ have special meaning when in double quotes那么"*"怎么会导致* @Karl-AnderoMere,因为在这种情况下它们根本没有作为参数展开。 "$@""$*" 是参数扩展。 "@""*" 不是。 @CharlesDuffy 谢谢,现在有意义了! Csh 风格的历史引用可能最好关闭;它们不是很有用,关闭它们可以帮助您避免讨厌的event not found 不带引号的感叹号错误消息。见***.com/questions/11816122/echo-fails-event-not-found @codeforester 我认为第 14 行的结果应该是 echo hi 被反引号包围。抱歉,我无法在评论中逃避反引号。【参考方案3】:

如果您指的是回显某些内容时会发生什么,单引号将逐字地回显它们之间的内容,而双引号将评估它们之间的变量并输出变量的值。

比如这个

#!/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

【讨论】:

【参考方案4】:

别人解释的很好,只想举个简单的例子。

单引号可用于文本周围,以防止外壳解释任何特殊字符。用单引号括起来的美元符号、空格、& 符号、星号和其他特殊字符都将被忽略。

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

它会给出这个:

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

唯一不能放在单引号内的是单引号。

双引号的作用类似于单引号,除了双引号仍然允许 shell 解释美元符号、反引号和反斜杠。众所周知,反斜杠会阻止解释单个特殊字符。如果需要将美元符号用作文本而不是变量,这在双引号中很有用。它还允许对双引号进行转义,因此它们不会被解释为带引号的字符串的结尾。

$ 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 

【讨论】:

【参考方案5】:

由于这是在处理 bash 中的引号时的实际答案,因此在处理 shell 中的算术运算符时,我将在上面的答案中再补充一点。

bash shell 支持两种算术运算方式,一种由内置的let 命令和$((..)) 运算符定义。前者对算术表达式求值,而后者更像是一个复合语句。

重要的是要了解let 使用的算术表达式会像任何其他shell 命令一样经历分词、路径名扩展。因此,需要进行适当的引用和转义。

使用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 字段。

【讨论】:

Charles Duffy 为 here 双引号提供了一个很好的案例 $((...))。例如,这可能是“有点”偏执,并且不太可能拥有IFS=0,但这当然不是不可能的:) 还有旧的$[[...]] 语法,但也许你忘记它是对的。【参考方案6】:

' '" " 的用法有明显区别。

' ' 用于任何事物时,不会进行“转换或翻译”。它按原样打印。

对于" ",无论它包围什么,都被“转换或转换”为它的值。

通过翻译/转换,我的意思是: 单引号内的任何内容都不会“翻译”为它们的值。它们将被视为在引号内。示例:a=23,然后echo '$a' 将在标准输出上产生$a。而echo "$a" 将在标准输出上产生23

【讨论】:

这个答案非常令人困惑,它并没有在现有的好答案之上添加任何内容。 在我看来,这是一个简短的回答,不会过于冗长,我很容易理解。当说翻译/转换时,它们的意思是双引号会扩展变量,而单引号不会扩展变量。 您所说的“转换或翻译”通常称为插值。表达式'foo $bar baz' 只是文字字符串foo $bar baz,而"foo $bar baz" 插值变量 bar 插入到文字符号 foobaz 之间的字符串中,中间有空格。 @tripleee 我只是想用最简单的方式解释一下。而且我想清楚的解释比使用正确的“同义词”更重要。它确实在不使用“插值”一词的情况下帮助了人们。【参考方案7】:

人们需要一个最低限度的答案才能开始工作,而不必像我一样花费大量时间。

令人惊讶的是(对于那些正在寻找答案的人来说)以下是一个完整的命令:

$ echo '\'

谁的输出是:

\

对于 bash 的长期用户来说,反斜杠在单引号内没有任何意义。其他也没有。

【讨论】:

以上是关于Bash中单引号和双引号的区别的主要内容,如果未能解决你的问题,请参考以下文章

浅谈PHP中单引号和双引号到底有什么区别呢?

php中单引号和双引号的区别,哪个速度更快?为啥?

MySQL中单引号,双引号和反引号的区别

Python中单引号,双引号和三引号的区别

SQL查询语句中单引号和双引号的问题

SQL查询语句中单引号和双引号的问题