我想将此命令放入一个文件中以便稍后运行:
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")
,然后在此处文档或其他地方的普通替换中使用它是安全的。