Section 21.1: 变量和命令替换的双引号

变量替换只能在双引号内使用。

calculation='2 * 3'
echo "$calculation" # prints 2 * 3
echo $calculation # prints 2, the list of files in the current directory, and 3
echo "$(($calculation))" # prints 6

在双引号之外,$var 获取 var 的值,将其拆分为以空格分隔的部分,并将每个部分解释为 glob (通配符) 模式。除非你想要这种行为,否则请始终将 $var 放在双引号内:"$var"。

这同样适用于命令替换:“$(mycommand)” 是 mycommand 的输出,$(mycommand) 是输出上 split+glob 的结果。

echo "$var" # good
echo "$(mycommand)" # good
another=$var # also works, assignment is implicitly double-quoted
make -D THING=$var # BAD! This is not a bash assignment.
make -D THING="$var" # good
make -D "THING=$var" # also good

命令替换有自己的引号上下文。编写任意嵌套的替换很容易,因为解析器将跟踪嵌套深度,而不是贪婪地搜索第一个 “ 字符。但是,StackOverflow 语法高亮工具会错误地解析此情况。例如:

echo "formatted text: $(printf "a + b = %04d" "${c}")" # “formatted text: a + b = 0000”

命令替换的变量参数也应在扩展中用双引号括起来:

echo "$(mycommand "$arg1" "$arg2")"

Section 21.2: 双引号和单引号的区别

双引号 单引号
允许变量扩展 禁止变量扩展
如果启用,则允许扩展历史记录 禁止历史记录扩展
允许命令替换 禁止命令替换
* 和 @ 可以具有特殊含义 * 和 @ 始终只是文本
可以同时包含单引号或双引号 单引号内不允许使用单引号

$, ", ' 可以使用转义符 \ 使其保持原来的字面意思,防止它们被解析为特殊含义

两者共同的属性:

  • 防止变量被扩展

  • 避免单词背分割

示例:

$ echo "!cat"
echo "cat file"
cat file
$ echo '!cat'
!cat
echo "\"'\""
"'"
$ a='var'
$ echo '$a'
$a
$ echo "$a"
var

Section 21.3: 换行符和控制字符

换行符可以包含在单引号字符串或双引号字符串中。请注意,引号中按换行键不会导致换行,换行符将被忽略。

newline1='
'
newline2="
"
newline3=$'\n'
empty=\
echo "Line${newline1}break"
echo "Line${newline2}break"
echo "Line${newline3}break"
echo "No line break${empty} here"

在美元符号后面的引号中,反斜线可用于转义符,就像在许多其他编程语言中一样。

echo $'Tab: [\t]'
echo $'Tab again: [\009]'
echo $'Form feed: [\f]'
echo $'Line\nbreak'

Section 21.4: 引用文本

本段中的所有示例都打印了该行

!"#$&'()*;<=>? @[\]^`{|}~

反斜杠引用下一个字符,即下一个字符按字面解释。一个例外是换行符:

backslash-newline 扩展为空字符串。

echo \!\"\#\$\&\'\(\)\*\;\<\=\>\?\ \ \@\[\\\]\^\`\{\|\}\~

单引号(正引号 ',也称为撇号)之间的所有文本都按字面意思打印。甚至反斜杠也代表自身,不可能包含单个引号; 相反,您可以停止文本字符串,包含带有反斜杠的文本单引号,然后再次启动文本字符串。因此,4 个字符的序列 ' 有效地允许在 Literals 字符串中包含单引号。

echo '!"#$&'\''()*;<=>? @[\]^`{|}~'

\# ^^^^

美元单引号以字符串文字 $'...' 开头与许多其他编程语言一样,其中反斜杠会引用下一个字符。

echo $'!"#$&\'()*;<=>? @[\\]^`{|}~'
\# ^^ ^^

双引号 " 分隔半文本字符串,其中只有字符 $ 和 ' 保留其特殊含义。

这些字符前面需要一个反斜杠(请注意,如果反斜杠后跟其他字符,则反斜杠仍然存在)。双引号在包含变量或命令替换时最有用。

echo "!\"#\$&'()*;<=>? @[\\]^\`{|}~"
\# ^^ ^^ ^^
echo "!\"#\$&'()*;<=>? @[\]^\`{|}~"
\# ^^ ^ ^^ \[ prints \[

交互时,请注意 !在双引号内触发历史记录扩展: "!oops" 查找包含 oops 的旧命令; "\!oops" 不进行历史扩展,但保留反斜杠。这在脚本中不会发生。