引号决定谁先解释字符
Shell 转义的本质是分层:Shell 先解释一层,命令自己再解释一层。单引号里除单引号本身外一切原样,双引号里美元符号、反引号、反斜杠与感叹号仍有含义,反斜杠则让紧随的一个字符失去特殊含义。写正则、JSON、sed 表达式这类本身就带转义的内容时,必须先想清楚哪一层负责解释哪个反斜杠。
基本信息
| 适用环境 | POSIX shell、bash、dash、zsh;PowerShell 规则不同 |
|---|---|
| 单引号 | 内部全字面量,无法在内部再转义单引号 |
| 双引号 | 仍会做变量展开、命令替换、反斜杠转义 |
| ANSI-C 引号 | $'...' 可写 \n、\t、\xHH、\uXXXX,属 bash/zsh 扩展 |
| 多行文本 | here-doc 用加引号的定界符关闭展开,适合粘贴脚本与 JSON |
典型使用场景
- 把含空格、括号的文件名传给命令,避免被拆词或当通配符展开
- 写 sed、awk 或 grep 的正则表达式,处理反斜杠翻倍
- 在脚本里嵌入一段 JSON 或 SQL,用 here-doc 保留原文
- 远程执行:ssh host 'cmd' 里再套一层引号,需要确认哪层剥壳
- 日志与审计:用 printf 打印变量原值,避免格式串被变量污染
分层写法示例
分层写法示例
echo "$name" # 变量值按原样传出,不做拆词
printf '%s\n' "$raw" # 打印任意内容,格式串与数据分离
regex='^[0-9]{3}-[0-9]{4}$' # 正则用单引号包住,Shell 不动它
grep -E "$regex" app.log # 传给 grep 的正则只解释一层
cat <<'EOF' > conf.json # 定界符加引号,正文不展开、原样落盘
{"path": "C:\\data", "user": "$HOME"}
EOF
ssh host 'cd /srv/app && ls' # 整条远端命令作为一个参数引号行为对照
| 写法 | 变量展开 | 路径通配 | 典型用途 |
|---|---|---|---|
| $var | 展开并拆词 | 会展开 | 几乎总是不该这么写 |
| "$var" | 展开不拆词 | 不展开 | 传参默认选择 |
| '$var' | 不展开 | 不展开 | 正则、JSON、字面量 |
| $'...' | 不展开 | 不展开 | 需要 \n、\t 等控制字符 |
| <<'EOF' | 不展开 | 不展开 | 多行原文输入 |
单引号内不能直接转义单引号,标准写法是关闭字符串、插入转义引号、再打开:'it'\''s'。这在拼接提交信息或 SQL 字面量时经常用到。
不要用双引号把外部输入拼成命令再交给 eval、sh -c 或数据库客户端,变量里带的分号与反引号会变成命令。需要构造命令时用数组或位置参数传值,而不是拼字符串。