在变量中转义双引号

在变量中转义双引号

我想将此命令放入一个文件中以便稍后运行:

ln -s "$xr"/ya.txt ~

我可以用(1)来做到这一点:

cat > zu.sh <<eof
ln -s "$xr"/ya.txt ~
eof

或(2):

printf 'ln -s "%s"/ya.txt ~\n' "$xr" > zu.sh

或(3):

echo "ln -s '$xr'/ya.txt ~" > zu.sh

或(4):

printf 'ln -s %q/ya.txt ~\n' "$xr" > zu.sh

或(5):

printf 'ln -s "%s"/ya.txt ~\n' "${xr//\"/\\\"}"

然而,每个解决方案都是有问题的。如果(1)或(2)中的变量包含双引号,则它们将失败;如果(3)中的变量包含单引号,则会失败。 (4) 不错,但不是由 POSIX 定义。 (5) 很好,但是 巴什主义。看起来最好的选择是使用 (1) 或 (2) 并转义变量中的任何双引号,但是可以通过其他方式完成吗?

答案1

我认为这是安全的:

esc() {
    printf "%s\n" "$1" | sed -e "s/'/'\"'\"'/g" -e "1s/^/'/" -e "\$s/\$/'/"
}

单引号字符串,因此输入字符串中的任何$, `, \, 和"都不重要,并将任何现有'字符转换为'"'"'(即结束单引号,双引号单独的单引号,然后重新输入单引号)。

很想使用$(...)命令替换在那里,除了它会吃掉输入中任何尾随的换行符。相反,开引号和收引号是由第二个和第三个插入的sed脚本本身,位于第一行的开头和最后一行的结尾。任何嵌入的换行符都保持原始状态,这很好。

输出适合复制回 shell,即使在我可以发明的最病态的情况下(使用Bash ANSI-C 引用$'...'首先创建测试字符串,但之后不创建):

bash-4.4$ esc $'abc\ndef ghi\'jkl$mno`pqr\\stu\\\'vwx\n\n\n'
'abc
def ghi'"'"'jkl$mno`pqr\stu\'"'"'vwx


'
bash-4.4$ echo 'abc
> def ghi'"'"'jkl$mno`pqr\stu\'"'"'vwx
>
>
> '
abc
def ghi'jkl$mno`pqr\stu\'vwx



bash-4.4$ dash
$ echo 'abc
def ghi'"'"'jkl$mno`pqr\stu\'"'"'vwx


'> > > >
abc
def ghi'jkl$mno`pqr\stu\'vwx



$

将其放入变量中xr=$(esc "$xr"),然后在此处文档或其他地方的普通替换中使用它是安全的。

相关内容