命令行参数中需要转义哪些字符?


14

在Bash中,当为命令指定命令行参数时,需要转义哪些字符?

他们是否限于猛砸的元字符:空格,制表 |&;()<,和>


不要忘记*和(可能的)文件名是否乱码?
杰夫·谢勒

谢谢。您能否详尽列出在cmd行args中需要转义的字符类型?
蒂姆

该列表很好,但是要了解有关引号的最重要的一点是:单引号之间的所有内容均按字面传递,并且不进行词拆分。 没有例外。(顺便说一句,这意味着没有办法将单引号嵌入单引号中,但是很容易解决。)
Wildcard

Answers:


22

以下字符在某些情况下对shell本身具有特殊含义,可能需要在参数中转义:

与我链接的那些字符相比,这些字符中的某些用于更多的事物和更多的地方。


有一些极端情况是明确可选的:


换行符转义需要引用 -反斜杠将无法完成工作。IFS中列出的任何其他字符将需要类似的处理。您不需要转义]},但是您确实需要转义,)因为它是一个运算符。

这些字符中的某些在何时真正需要转义时比其他字符有更严格的限制。例如,a#b可以,但是a #b是注释,而>在两种情况下都需要转义。无论如何,保守地逃避它们并没有什么害处,而且比记住精细的区别还容易。

如果你的命令名字本身就是一个壳的关键字(iffordo),那么你就需要逃跑或引用它。其中唯一有趣的是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,则目前是安全的。


您所在区域的其他空白需要转义以及(目前不包括存在一个bug的多字节一个
斯特凡Chazelas

!在启用csh历史记录扩展时才需要转义(通常不在脚本中)。[ ! -f a ]还是find . ! -name...很好。您的更严格的限制部分对此进行了介绍,但也许值得一提。
斯特凡Chazelas

请注意,还有其他地方需要的字符引用像背景:hash[foo"]"]=${var-foo"}"}[[ "!" = b ]][[ a = "]]" ]],正则表达式运营商[[ x =~ ".+[" ]]。其他关键字比{ifwhilefor...)将需要被引用所以他们不会承认的......
斯特凡Chazelas

就那些根本不是命令行参数而言,解释取决于所讨论的命令(就像]),因此我没有列出它们。我认为任何关键字都不需要在参数位置加引号。
Michael Homer

2
引用内置函数,破折号或%不会执行任何操作。
Michael Homer

3

在GNU Parallel中,这已经过测试和广泛使用:

$a =~ s/[\002-\011\013-\032\\\#\?\`\(\)\{\}\[\]\^\*\<\=\>\~\|\; \"\!\$\&\'\202-\377]/\\$&/go;
# quote newline as '\n'                                                                                                         
$a =~ s/[\n]/'\n'/go;

这是在测试bashdashashkshzsh,和fish。某些字符不需要在外壳的某些(版本)中加引号,但以上字符适用于所有经过测试的外壳。

如果只想用引号引起来,则可以将其传递到parallel --shellquote

printf "&*\t*!" | parallel --shellquote

我怎么没听说过平行运动……
汤姆H

@TomH如果您能花5分钟思考我们如何联系您,将不胜感激。
Ole Tange '18

我认为这是一个进步问题。大多数人只有在经历了一些复杂性阶段后才需要并行或理解。到那时,他们遇到了xargs,nohup和类似的东西。同样,我也没有看到很多人使用并行来解决堆栈交换中的问题,或者当我用谷歌搜索bash问题的解决方案时
Tom H

1

对于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

是的,这一点很有效。我的观点是,大多数人都会进入该页面,因为他们有一个要解决的问题。不是因为这引起了有趣的学术辩论。这就是为什么我想提供解决方案并讨论它们的优点的原因,即使有些偏离主题。
加里·特尔基亚

我的代码只是Michael Homer答案的实现。我无意提供比他更多的信息。
加里·特尔基亚
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.