带有\ s +的反引号grep调用,抛出“无法识别的转义\ s通过”

时间:2019-01-08 22:30:39

标签: regex perl escaping system

从我的Perl代码中,我想执行系统调用

$grepp = `grep 'output\s+reg' $file`;

但我保留

Unrecognized escape \s passed through at

您能帮助我理解此错误吗?

1 个答案:

答案 0 :(得分:1)

在双引号和其他类似的字符串文字中,例如反引号,\对Perl来说很重要。

\后跟非单词字符(例如\或其他符号)只会导致转义字符。

\后跟一些单词字符具有特殊含义(例如\n导致换行,\x0A也是如此)。当\后跟一个Perl没有意义的单词字符(例如\s)时,您会收到该警告,因为您的代码不向前兼容。通过转义\使代码向前兼容,可以避免警告。

my $grepp = `grep 'output\\s+reg' $file`;   # Executes: grep 'output\s+reg' some file.txt

除了您所问的问题之外,该代码还有两个主要问题。

第一个主要是代码注入错误。您正在将文本(文件名)插入代码(shell命令)而不进行任何形式的转换。如果文件名包含任何外壳程序元字符(例如空格,(;等),则此操作将失败,并且恶意行为者可能会利用此错误来执行破坏性命令。

String::ShellQuoteshell_quote可用于避免此问题。

use String::ShellQuote qw( shell_quote );

my $cmd = shell_quote('grep', 'output\s+reg', $file);
my $grepp = `$cmd`;

您还可以避免使用以下模块并避免创建外壳:

open(my $pipe, '-|', 'grep', 'output\s+reg', $file);
my $grepp = '';
$_ .= $grepp while <$pipe>;
close($pipe);

第二个主要问题是您提供的模式并不意味着您认为的那样。 grep默认使用的正则表达式模式语言与Perl完全不同。您需要以下之一:

output[[:space:]]\+reg       # Without -E or -P

output\s\+reg                # Without -E or -P. Less portable

output\s+reg                 # With -E or -P

因此,以下是最终代码:

use String::ShellQuote qw( shell_quote );

my $cmd = shell_quote('grep', '-E', 'output\s+reg', $file);
my $grepp = `$cmd`;

当然,人们不得不怀疑为什么您执行grep实用程序而不是自己在Perl中执行搜索。