![bash 提示中使用反斜杠转义特殊字符进行字符串操作](https://linux22.com/image/205383/bash%20%E6%8F%90%E7%A4%BA%E4%B8%AD%E4%BD%BF%E7%94%A8%E5%8F%8D%E6%96%9C%E6%9D%A0%E8%BD%AC%E4%B9%89%E7%89%B9%E6%AE%8A%E5%AD%97%E7%AC%A6%E8%BF%9B%E8%A1%8C%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%93%8D%E4%BD%9C.png)
我希望我的 bash 提示符\etc\defaults
在PS1
我处于/etc/defaults
.
我尝试过这两种方法
PS1="$(echo "\w" | sed 's/\//\\/g')"
PS1="$(tmp="\w" && echo ${tmp//\//\\})"
但两者的结果都是/etc/defaults
.
我觉得很奇怪,因为两者
echo $PWD | sed 's/\//\\/g'
tmp=$PWD && echo ${tmp//\//\\}
打印\etc\defaults
。
答案1
不管我们如何看待用反斜杠替换斜杠,这实际上是一个有趣的引用地狱问题。一个会提出其他类似结构的人。
如果你PS1
包含$(echo "\w" | sed 's/\//\\/g')
,会发生什么第一的Bash 处理它以进行提示转义,例如\w
.所以echo "\w"
变成echo "/etc/defaults"
,它基本上适用于好的路径名。但同时,它也把 变成了\\
单一的\
……所以你需要进入的PS1
,是$(echo "\w" | sed -e 's/\\//\\\\/g')
。或者使用双引号,与更多反斜杠相同: $(echo "\w" | sed -e "s/\\\\//\\\\\\\\/g")
.
然后就是问题任务到PS1
,在那里,您可能需要一个单引号字符串,它必须包含单引号,因此您需要将它们替换为'\''
.它变成这样:
PS1='$(echo "\w" | sed -e '\''s/\\//\\\\/g'\'')'
这很尴尬,SE 语法荧光笔似乎没有正确遵循它,它将'\''
s 之间的部分显示为未引用的部分。
但是......有更好的方法可以做到这一点。
这种\w
替换有点可疑,因为在 shell 命令行上直接文本替换数据基本上会带来麻烦。如果路径是/tmp/quote"me
,则直接替换将产生echo "/tmp/quote"me"
,并带有杂散引号。 Bash 实际上确实添加了反斜杠来转义引号,所以它变成了echo "/tmp/quote\"me"
,这是可以的。但它仍然很恶心,所以我宁愿避免它。如果转义与解析不匹配,则可能存在一个非常合理的命令注入问题。例如类似的echo '\w'
会不是工作,如果路径包含任何"$\
,它会导致额外的反斜杠出现,并且如果它包含'
. (与 SQL 注入类似的问题。)
此外,我们可以通过定义一个函数来运行该函数,从而从提示符本身中sed
隐藏命令,从而摆脱引用地狱。s///
顺便说一句,我们必须$PWD
在这里使用,因为该函数本身不是提示的一部分,所以\w
不起作用:
manglepath() {
echo "$PWD" | sed 's/\//\\/g'
}
PS1='$(manglepath)\$ '
实际上我们应该能够使用${var//pattern/replacement}
扩展而不是调用sed
,并且我们可能应该使用printf
代替echo
:
manglepath() {
printf "%s\n" "${PWD//\//\\}"
}
PS1='$(manglepath)\$ '
答案2
PS1='$(echo "\w" | sed '\''s#/#\\\\#g'\'')'
这将导致 PS1$(echo "\w" | sed 's#/#\\\\#g')