如何在 Bourne Shell 中回显包含 $ 的转义字符串?
user@server:~$ cat test.sh
#!/bin/sh
echo $1
user@server:~$ ./test.sh \$sad\$test
$sad$test
我希望它返回这样的转义版本:
user@server:~$ ./test.sh \$sad\$test
\$sad\$test
我尝试过用 sed 和 awk 做一些技巧,但没有成功。任何指导将不胜感激。
答案1
我假设您希望字符串显示为“外壳引用”。
这打印函数内置命令在克什,巴什, 和桀骜都理解%q
格式说明符。实际输出未标准化,可能会根据输入字符串而变化(见下文)。由于输出形式的变化,您可能无法将一个 shell 的输出与另一个 shell 一起使用(特别是如果您的目标 shell 是一个功能不太丰富的 shell,例如灰,短跑, ETC。)。
桀骜还支持直接在参数扩展中生成引号:
echo "${(q)1}" # backslashes, with $'' for unprintable/invalid characters
echo "${(qq)1}" # single quotes
echo "${(qqq)1}" # double quotes
echo "${(qqqq)1}" # $'' quoting
如果你想“自己动手”,最简单、最可靠的事情就是生成你自己的单引号。一个简单的算法如下:
- 将任何单引号更改为序列
'\''
。 - 将结果用单引号引起来。
这适用于类似 Bourne 的 shell,因为单引号完全是字面意思1。要表示单引号,请结束当前的单引号范围,提供反斜杠转义的单引号并恢复对字符串的其余部分进行单引号。上面的算法在处理连续的单引号以及字符串开头和结尾的单引号时效率较低,但它非常可靠并且实现起来非常简单。
1其他语言中的单引号通常并不完全是字面意思(至少,它们通常允许一些有限的反斜杠转义)。这就是为什么了解您将生成的引用形式的所有引用规则(即在什么语言/上下文中将使用引用的文本)至关重要。
以下是printf %q
我本地安装的 shell 中的一些示例:
for s in /bin/ksh {,/opt/local}/bin/bash {,/opt/local}/bin/zsh
do
"$s" --version | head -1
"$s" -c 'printf "%q\n" "$@"' - \$sad\$test \'mixed\ quotes\" back\`tick
echo
done
输出:
version sh (AT&T Research) 1993-12-28 s+
'$sad$test'
$'\'mixed quotes"'
'back`tick'
GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin10.0)
\$sad\$test
\'mixed\ quotes\"
back\`tick
GNU bash, version 4.2.10(2)-release (i386-apple-darwin10.7.0)
\$sad\$test
\'mixed\ quotes\"
back\`tick
zsh 4.3.9 (i386-apple-darwin10.0)
\$sad\$test
\'mixed\ quotes\"
back\`tick
zsh 4.3.12 (i386-apple-darwin10.7.0)
\$sad\$test
\'mixed\ quotes\"
back\`tick
我们看到克什似乎“喜欢”用单引号引用,并$''
在某些情况下使用这种形式。其他 shell 似乎主要使用反斜杠转义(尽管$''
如果存在某些字符,它们也会使用)。
答案2
将单引号括起来\$sad\$test
:
$ echo $SHELL
/bin/bash
$ ./test.sh '\$sad\$test'
\$sad\$test
答案3
通过执行test.sh \$sad\$test
,test.sh
脚本接收$sad$test
作为其参数,而不是\$sad\$test
。原因是 shell在调用之前替换了\$
by 。如果您希望脚本接收,您应该执行或。$
test.sh
\$sad\$test
test.sh '\$sad\$test'
test.sh "\\\$sad\\\$test"
试试这个来说服自己:
function cat1stpar() {
cat << EOF
$1
EOF
}
cat1stpar \$sad\$test
cat1stpar '\$sad\$test'
cat1stpar "\\\$sad\\\$test"
另外,在一般情况下,使用echo $1
是危险的。如果你这样做:
./test.sh "aaa bbb"
./test.sh "aaa bbb"
输出将是:
aaa bbb
aaa bbb
并不是:
aaa bbb
aaa bbb
如果你想要第二个输出,你至少应该这样做,echo "$1"
以确保echo
接收到一个参数,而不是那么多字1 美元。有关完整的单词讨论,请参阅 shell man 中的 IFS 变量。
也有人说这样做比在打印之前更改一些字符printf "%s\n" "$1"
更安全,但我还没有完全理解。echo "$1"
echo
编辑:
关于echo
改变字符,我只是明白了。尝试:
echo "-n"
printf "%s\n" "-n"
./test.sh "-n"
cat1stpar "-n"
答案4
在脚本中:
echo "${1//$/\\$}"
这是 shell 中构建的简单字符串替换。该语法${[VARIABLE_NAME]//[PATTERN]/[REPLACEMENT]}
用于全局文字字符串替换。
不知道你为什么要这样做。该脚本实际上只是报告您发送给它的字符串;\$sad\$test
计算结果与 完全相同的字符串'$sad$test'
,除了后者使用单引号来转义$
。