1 不是一回事!
在 bash 中,单引号 '
与 双引号 "
具有不同的意义。
简单的说,
- 单引号 包裹的内容不作变量解析、字符转义操作,只作为普通纯文本原样输出。
- 双引号 包裹的内容会进行变量解析、字符转义等操作。
参考资料:
2 嵌套特殊需求
执行以下命令,期待打印一段字符串到受保护的文件中
sudo bash -c "echo '#!/bin/sh' >> /usr/local/TEST_FILES"
原本以为会在 /usr/local/TEST_FILES
中写入以下内容:
#!/bin/sh
而实际情况却是命令出错:
bash: !/bin/sh': event not found
为什么会这样的?
参见这里 的 Event Designators 部分。一个 designator(指示器)表示对历史命令中的某一项的引用;叹号 !
可以作为命令的一部分,其后跟不同的字符表示不同的引用。也就是说 叹号
后紧接着的不是 (空格)
、 (制表符)
、(行结束符)
、=
、(
的话,都可以表示一条命令。(参)如:
!n 执行第n个命令
!! 执行上一个命令
!STRING 执行最近一次以STRING开头的命令
## 执行历史命令
# !! 运行上一条命令
# !88 运行第88条命令
# !ca 运行上一个包含ca的命令
所以出错原因就是 !/bin/sh'
被解析成了一个命令引用,而幸好没有执行过的命令中没有以之开头的,所以直接报错而不是直接执行了。
3 解决办法
既然单引号是不做转义处理,那么我们把两种引号的位置互换以下,直接用 单引号包裹命令如何?即:
sudo bash -c 'echo "#!/bin/sh" >> /usr/local/TEST_FILES'
结果表明这是可行的。
当然也有一种不优雅的办法,就是嵌套单引号, 即:
sudo bash -c $'echo ‘#!/bin/sh’ >> /usr/local/TEST_FILES'
4 题外话
引号问题依旧很迷,因为,直接输入以下命令:
echo "#!/bin/sh"
却依旧是命令出错:
bash: !/bin/sh“: event not found
这也就是说,在 bash -c STRING
的 字面命令字符 STRING
中 双引号的行为 与 bash 命令参数中的双引号 的行为 是不一致的。
是否可以总结:
- 单引号: 字面串
- 双引号: 解析串
- 命令行默认:解析串
a=apple
echo $a #apple
echo "$a" #apple
echo '$a' #$a
echo ‘"$a"’ #"$a"
echo "'$a'" #'apple'
5 结论
结合讨论difference-between-single-quoted-string-and-double-quoted-string以及其中提到的网站
"weak quote"
'strong quote'
$'C String'
: 使用 C语言那种转义规则处理单引号的字符串,得到的结果依旧是被单引号包裹的,即结果字符串是在强引用的作用范围内。$"I18N String"
:根据 当前 locale,如果有可用的翻译,将用翻译替换双引号内的字符串,得到的结果依旧是被双引号包裹的,即结果字符串是在弱引用的作用范围内。
进一步了解,可以查阅手册的相关介绍
如需转载请注明出处!