双引号内嵌套双引号必须用"转义;单引号内双引号无需转义但无法展开变量;混合引号时仅双引号段支持变量替换;复杂场景应优先使用数组或$()替代硬转义。

双引号内需要嵌套双引号时必须用 转义
直接在双引号字符串里写 " 会导致 Shell 提前结束字符串解析,报错 unexpected EOF while looking for matching `"' 。唯一安全的方式是用反斜杠转义: "He said "Hello""。注意, 只对紧随其后的字符生效,且仅在双引号或无引号上下文中有效——单引号里 完全失效。
常见错误场景:
- 拼接 JSON 字符串:
json="{"name":"Alice"}"✅;写成json="{"name":"Alice"}"❌ - 构造 curl 请求体:
curl -d "{"id":123}" http://api/✅;漏掉转义会触发语法错误
单引号内部无法转义双引号,但可以拼接混用
单引号是“强引用”,里面所有字符(包括 、$、`)都按字面处理,所以 'say "hi"' 是合法的——双引号在单引号里不具特殊含义,无需也不允许转义。但如果你真要插入一个单引号字符,不能写 'it's',而得拆开:'it'''s',即 'it' + ' + 's'。
这种拼接本质是 Shell 的词法合并规则,不是字符串连接操作。示例:
-
echo 'He said "'hello'"'→ 输出He said "hello" -
echo 'Don'''t do that'→ 输出Don't do that
混合使用单双引号时,变量和命令替换只在双引号段生效
Shell 按词(word)切分后逐段解析,所以 "prefix $var" 'suffix' 中,只有第一段支持变量展开,第二段完全静态。这常被误用于“绕过引号限制”,但要注意语义断裂风险。
典型陷阱:
-
cmd="ls -l" ' *.txt'❌ —— 这不是拼接,而是两个独立参数,ls -l后没空格,*.txt不会被 glob 展开 - 正确做法是统一用双引号并转义:
"$cmd *.txt"或更安全地用数组:args=("ls" "-l" "*.txt"); "${args[@]}"
真正复杂的嵌套建议改用 $() 和数组,而不是硬扛引号
当命令里同时含变量、单引号、双引号、换行和重定向时,靠引号嵌套极易出错。比如想动态生成一条带注释的 sed 替换命令:sed -i "s/'old'/"new"/g" file 已经很难读了,再加变量就失控。
更可靠的做法:
- 用
$()分离逻辑:pattern=$(printf '%s' "$old" | sed 's/[&/]/\&/g'),再代入 - 用数组存参数:
cmd=(sed -i "s/$old/$new/g" "$file"),最后执行"${cmd[@]}" - 必要时写临时函数封装,避免一行塞太多东西
引号规则本身简单,但人脑对嵌套层次的跟踪能力有限。一旦超过两层引号混合,优先考虑结构化替代方案,而不是死磕转义。


















