Answers:
以下字符在某些情况下对shell本身具有特殊含义,可能需要在参数中转义:
` 反t(U + 0060 Grave Accent)~ 蒂尔德(U + 007E)! 感叹号(U + 0021)# 哈希(U + 0023数字符号)$ 美元符号(U + 0024)& &符(U + 0026)* 星号(U + 002A)( 左括号(U + 0028)) 右括号(U + 0029) (⇥)标签(U + 0009){ 左支架(U + 007B左弯形支架)[ 左方括号(U + 005B)| 竖线(U + 007C竖线)\ 反斜杠(U + 005C反固相线); 分号(U + 003B)' 单引号/撇号(U + 0027)" 双引号(U + 0022)↩ 换行(U + 000A)< 小于(U + 003C)> 大于(U + 003E)? 问号(U + 003F) 空格(U + 0020)1与我链接的那些字符相比,这些字符中的某些用于更多的事物和更多的地方。
有一些极端情况是明确可选的:
!可以使用禁用set +H,这是非交互式外壳中的默认设置。{可以通过禁用set +B。*并且?可以与被禁用set -f或set -o noglob。=如果set -k或set -o keyword启用,等号(U + 003D)也需要转义。换行符转义需要引用 -反斜杠将无法完成工作。IFS中列出的任何其他字符将需要类似的处理。您不需要转义]或},但是您确实需要转义,)因为它是一个运算符。
这些字符中的某些在何时真正需要转义时比其他字符有更严格的限制。例如,a#b可以,但是a #b是注释,而>在两种情况下都需要转义。无论如何,保守地逃避它们并没有什么害处,而且比记住精细的区别还容易。
如果你的命令名字本身就是一个壳的关键字(if,for,do),那么你就需要逃跑或引用它。其中唯一有趣的是in,因为它并不总是一个关键字,这一点并不明显。你并不需要做的是在辩论中使用的关键词,只有当你(愚蠢!)其中一人的名字命名的命令。Shell运算符((,&等)始终需要在任何地方引用。
1 斯特凡指出,任何其他单字节从您的区域空白字符也需要转义。在最常见的明智语言环境中,至少是基于C或UTF-8的语言环境,只是上面的空白字符。在某些ISO-8859-1语言环境中,U + 00A0的不间断空格被视为空白,包括Solaris,BSD和OS X(我认为不正确)。如果您要处理的是任意未知的语言环境,那么它可能几乎包括任何内容(包括字母),祝您好运。
可以想象,被认为是空白的单个字节可能出现在非空白的多字节字符中,并且除了将整个内容都用引号引起来之外,您没有其他方法可以转义。这不是理论上的问题:在上面的ISO-8859-1语言环境中A0,可以认为该字节为空白的字节可以出现在多字节字符中,例如UTF-8编码的“à”(C3 A0)。为了安全地处理这些字符,您需要引用它们"à"。此行为取决于运行脚本的环境中的语言环境配置,而不是您编写脚本的环境。
我认为这种行为从多种方面打破了,但我们必须发挥自己的作用。如果您正在使用任何非自同步多字节字符集,则最安全的方法是引用所有内容。如果您使用的是UTF-8或C,则目前是安全的。
!在启用csh历史记录扩展时才需要转义(通常不在脚本中)。[ ! -f a ]还是find . ! -name...很好。您的更严格的限制部分对此进行了介绍,但也许值得一提。
hash[foo"]"]=,${var-foo"}"},[[ "!" = b ]],[[ a = "]]" ]],正则表达式运营商[[ x =~ ".+[" ]]。其他关键字比{(if,while,for...)将需要被引用所以他们不会承认的......
]),因此我没有列出它们。我认为任何关键字都不需要在参数位置加引号。
在GNU Parallel中,这已经过测试和广泛使用:
$a =~ s/[\002-\011\013-\032\\\#\?\`\(\)\{\}\[\]\^\*\<\=\>\~\|\; \"\!\$\&\'\202-\377]/\\$&/go;
# quote newline as '\n'
$a =~ s/[\n]/'\n'/go;
这是在测试bash,dash,ash,ksh,zsh,和fish。某些字符不需要在外壳的某些(版本)中加引号,但以上字符适用于所有经过测试的外壳。
如果只想用引号引起来,则可以将其传递到parallel --shellquote:
printf "&*\t*!" | parallel --shellquote
对于Perl中的轻量级转义解决方案,我遵循单引号的原则。单引号中的Bash字符串可以包含任何字符,但单引号本身除外。
我的代码:
my $bash_reserved_characters_re = qr([ !"#$&'()*;<>?\[\\`{|~\t\n]);
while(<>) {
if (/$bash_reserved_characters_re/) {
my $quoted = s/'/'"'"'/gr;
print "'$quoted'";
} else {
print $_;
}
}
示例运行1:
$ echo -n "abc" | perl escape_bash_special_chars.pl
abc
示例运行2:
echo "abc" | perl escape_bash_special_chars.pl
'abc
'
示例运行3:
echo -n 'ab^c' | perl escape_bash_special_chars.pl
ab^c
示例运行4:
echo -n 'ab~c' | perl escape_bash_special_chars.pl
'ab~c'
示例运行5:
echo -n "ab'c" | perl escape_bash_special_chars.pl
'ab'"'"'c'
echo 'ab'"'"'c'
ab'c