Bash双引号内printf输出反斜杠数量异常问题咨询
Bash双引号中printf输出反斜杠的转义逻辑
问题场景
在Bash双引号中使用printf输出反斜杠时,出现了看似反常的结果:
- 双引号内写2个反斜杠,输出1个;写4个反斜杠,还是输出1个
- 写6个反斜杠输出2个,写8个输出2个,10个则输出3个
环境信息
povje@povje:~$ which bash /bin/bash povje@povje:~$ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 20.04.5 LTS Release: 20.04 Codename: focal
测试命令及输出
povje@povje:~$ printf "\\" \povje@povje:~$ printf "\\\\" \povje@povje:~$ printf "\\\\\\" \\povje@povje:~$ printf "\\\\\\\\" \\povje@povje:~$ printf "\\\\\\\\\\" \\\povje@povje:~$
转义逻辑拆解
这个过程分两个先后阶段处理,每阶段的转义规则叠加导致了最终的结果:
阶段1:Bash的命令行参数解析
Bash在执行命令前,会先处理双引号内的内容,核心规则是:
双引号内,每2个连续的反斜杠会被合并成1个普通的反斜杠;如果最后剩余单个反斜杠,也会保留为1个普通反斜杠(除非它用来转义双引号、美元符等特殊字符)。
对应规则的实际效果:
- 双引号内2个
\→ Bash解析后得到1个\ - 双引号内4个
\→ Bash解析后得到2个\ - 双引号内6个
\→ Bash解析后得到3个\ - 以此类推,N个双引号内的
\,经过Bash解析后得到N/2个\(整数除法)
阶段2:printf的格式字符串解析
printf会把接收到的第一个参数当作格式字符串处理,核心规则是:
格式字符串中,每2个连续的反斜杠会被解析成1个输出的反斜杠;如果最后剩余单个反斜杠,直接输出这个反斜杠。
对应规则的实际效果:
- 传给printf的1个
\→ 直接输出1个\ - 传给printf的2个
\→ 解析后输出1个\ - 传给printf的3个
\→ 前2个解析成1个,剩下1个直接输出,总共2个\ - 传给printf的4个
\→ 每2个一组解析,输出2个\ - 传给printf的5个
\→ 前4个解析成2个,剩下1个输出,总共3个\
对应测试命令的完整流程
把两个阶段结合起来,对应每个测试命令的结果:
printf "\\"(双引号内2个\)- Bash解析后得到1个
\→ printf直接输出1个\
- Bash解析后得到1个
printf "\\\\"(双引号内4个\)- Bash解析后得到2个
\→ printf解析成1个\输出
- Bash解析后得到2个
printf "\\\\\\\\"(双引号内6个\)- Bash解析后得到3个
\→ printf解析成2个\输出
- Bash解析后得到3个
printf "\\\\\\\\"(双引号内8个\)- Bash解析后得到4个
\→ printf解析成2个\输出
- Bash解析后得到4个
printf "\\\\\\\\\\"(双引号内10个\)- Bash解析后得到5个
\→ printf解析成3个\输出
- Bash解析后得到5个
总结
之所以会出现“每两组双引号内的反斜杠被忽略一组”的错觉,是因为Bash和printf都对反斜杠做了“每两个合并为一个”的转义处理,两次叠加后,相当于每4个双引号内的反斜杠最终只输出1个,每6个输出2个,以此类推。如果想要直接输出N个反斜杠,最简单的方法是用单引号包裹格式字符串(单引号内Bash不会处理转义),比如printf '\\'输出1个\,printf '\\\\'输出2个\,以此类推。
内容的提问来源于stack exchange,提问作者bryrup
相关产品推荐
相关产品推荐

