ChatGPT解决这个技术问题 Extra ChatGPT

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

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

另请参阅(可能的跨站点重复):来自 Unix & 的 What is the difference between “…”, '…', $'…', and $“…” quotes? Linux 堆栈交换
标题是 Bash,但这确实适用于任何与 Bourne 兼容的 shell(经典的 Bourne shell、POSIX shashdashksh 和 - 有一些警告 - zsh)。

c
codeforester

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

例子:

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

Bash 手册有这样的说法:

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


对于不知道“插值”是什么意思的人: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,你仍然没有提示)。
注意:$ name='O'Hara' 不合法,但 $ name='O'\''Hara' 有效。即使单引号之间的单引号不合法,您也可以通过将每个 ' 替换为 '\'' 而没有空格来转义它。
J
John Kugelman

accepted answer 很棒。我正在制作一个有助于快速理解该主题的表格。解释涉及一个简单的变量 a 以及一个索引数组 arr

如果我们设置

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

然后 echo 第二列中的表达式,我们将得到第三列中显示的结果/行为。第四列解释了行为。

表达式 结果 注释 1 "$a" apple 变量在 "" 内展开 2 '$a' $a 变量在 '' 内不展开 3 "'$a'" 'apple' '' 在 "" 内没有特殊含义 4 '"$a"' "$a" "" 被视为字面意思 inside '' 5 '\'' invalid can't escape a ' within '';使用 "'" 或 $'\'' (ANSI-C 引用) 6 "red$arocks" red $arocks 不扩展 $a;使用 ${a}rocks 保存 $a 7 "redapple$" redapple$ $ 后跟没有变量名 计算结果为 $ 8 '\"' \" \ 在 '' 9 "\'" \' \' 内没有特殊含义在 "" 内解释,但对 ' 10 "\"" " \" 在 "" 11 "*" 内解释 * glob 在 "" 或 '' 12 "\t\n" \t\n 内不起作用\t 和 \n 在 "" 或 '' 内没有特殊含义;使用 ANSI-C 引用 13 "`echo hi`" hi `` 和 $() 在 "" 内求值(反引号保留在实际输出中) 14 ' `echo hi`' `echo hi` `` 和 $() 不在 '' 内部求值(反引号保留在实际输出中) 15 '${arr[0]}' ${arr[0]} 无法访问数组inside '' 16 "${arr[0]}" apple array access works inside "" 17 $'$a\'' $a' 单引号可以在 ANSI-C quoting 18 "$'\t'" $ 内转义'\t' ANSI-C 引用不会在 "" 19 '!cmd' !cmd 历史扩展字符 '!' 内解释在 '' 20 "!cmd" cmd args 中被忽略 扩展为匹配 "cmd" 21 $'!cmd' 的最新命令 !cmd 历史扩展字符 '!'在 ANSI-C 引号内被忽略

也可以看看:

ANSI-C 引用 $'' - GNU Bash 手册

使用 $"" 进行语言环境翻译 - GNU Bash 手册

报价的三点公式


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

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

例如,这个

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

S
Sreehari

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

可以在文本周围使用单引号,以防止 shell 解释任何特殊字符。美元符号、空格、& 符号、星号和其他特殊字符在用单引号括起来时都会被忽略。

$ 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 

I
Inian

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

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

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

使用 let 时请参阅此示例

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

在这里使用单引号绝对没问题,因为这里不需要变量扩展,请考虑以下情况

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

会惨败,因为单引号下的 $barnot 扩展并且需要双引号作为

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,但这当然不是不可能的 :)
还有遗留的 $[[...]] 语法,但也许你忘记它是对的。
t
tripleee

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

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

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

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


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

人们需要一个最小的答案,而不需要像我一样花费大量时间。

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

$ echo '\'

其输出是:

\

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