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

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

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

它们是否仅限于 Bash 的元字符:空格 、制表符|、、、、、、、、和?&;()<>

答案1

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

特点 统一码 姓名 用法
` U+0060(重音) 反引号 命令替换
~ 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(空白)

其中一些字符比我链接的字符用于更多的事情和更多的地方。


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


转义换行符需要引用— 反斜杠不起作用。中列出的任何其他字符IFS将需要类似的处理。你不需要逃避]或者},但是你需要转义,)因为它是一个运算符。

其中一些角色在真正需要逃跑时比其他角色有更严格的限制。例如,a#bis ok,but a #bis a comment,而>在两种情况下都需要转义。无论如何,保守地避开它们并没有什么坏处,而且这比记住细微的区别更容易。

如果您的命令名称本身是 shell 关键字 ( if, for, do),那么您也需要对其进行转义或引用。其中唯一有趣的是in,因为它始终是一个关键字并不明显。你仅当您(愚蠢地!)以其中一个关键字命名命令时,才需要对参数中使用的关键字执行此操作。 Shell 运算符((&等)无论在哪里都始终需要引用。


1 Stéphane 指出任何其他单字节您所在区域的空白字符也需要逃避。在最常见、合理的语言环境中,至少是基于 C 或 UTF-8 的语言环境中,它只是上面的空白字符。在某些 ISO-8859-1 语言环境中,U+00A0 不间断空格被视为空白,包括 Solaris、BSD 和 OS X(我认为不正确)。如果您正在处理任意未知的区域设置,它可能包括任何内容,包括字母,所以祝您好运。

可以想象,可能会出现被视为空白的单个字节之内一个非空白的多字节字符,除了将整个字符放在引号中之外,您没有办法逃脱它。这不是理论上的问题:在上面的 ISO-8859-1 语言环境中,A0可能会出现被视为空白的字节之内多字节字符,例如 UTF-8 编码的“à”( C3 A0)。为了安全地处理这些字符,您需要引用它们"à"。此行为取决于运行脚本的环境中的区域设置配置,而不是您编写脚本的环境中的区域设置配置。

我认为这种行为可以通过多种方式被打破,但我们必须按照我们所发的牌来打。如果您正在使用任何非自同步多字节字符集,最安全的做法是引用所有内容。如果您使用 UTF-8 或 C,那么您(目前)是安全的。

答案2

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

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

它在bashdashashkshzsh和中进行了测试fish。某些字符在某些(版本)shell 中不需要引用,但上述内容在所有经过测试的 shell 中都有效。

如果您只想引用一个字符串,可以将其通过管道传输到parallel --shellquote

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

答案3

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

相关内容