0

为什么这两个命令的输出不同?

cat config.xml|perl -ne 'print $1,"\n" if /([0-9\.]+):161/'

cat config.xml|perl -ne "print $1,"\n" if /([0-9\.]+):161/"

首先按预期打印匹配组,而秒打印整行。

4

3 回答 3

5

我发现您的命令有两个主要问题。

首先,双引号允许 shell 插值,$1并将被用作 shell 变量并被替换。由于它不太可能存在,它将被替换为空字符串。因此print $1,您会得到print,而不是 ,它是 的简写print $_,并且可能是打印整行的原因。

其次,您的命令中有未转义的双引号,因此您实际上是在将三个字符串传递给 Perl:

print ,
\n
 if /(....)/

至于为什么或如何与您的 shell 一起工作,我不知道,因为我无法访问您的操作系统,也不知道它是哪一个。在 Windows 中,我收到n( Unquoted string "n" may clash with future reserved word at -e line 1.) 的 Perl 裸字警告,这意味着\n被解释为字符串。现在,这是棘手的部分。我们得到的是这样的:

print , \n if /.../

这意味着 that\n不再是 的参数print,它是紧随其后的语句,print并且处于无效上下文中,因此被忽略。我们可以通过这个警告看到这一点(我不得不在我的 shell 中伪造):

Useless use of single ref constructor in void context at -e line 1.

(请注意,您不会收到这些警告,因为您不使用警告——-w开关)

所以我们剩下的就是

print if /.../

这正是您描述的行为的代码:找到匹配项时打印整行。

要在 shell 中可视化问题,您可以将-MO=Deparse开关添加到单行中,如下所示:

C:\perl>perl -MO=Deparse -ne"print ,"\n" if /a/"
LINE: while (defined($_ = <ARGV>)) {
    print($_), \'n' if /a/;
}
-e syntax OK

现在我们可以清楚地看到 print 语句与换行符是分开的,并且换行符是对字符串的引用。


解决方案:

但是,您的代码还有其他问题,如果处理得当,您可以避免所有 shell 困难。首先,你有一个UUOC(无用的 Cat)-n在命令行上使用开关时,可以给 perl 一个文件参数。其次,您不需要为此使用变量,您可以简单地打印正则表达式的返回值:

perl -nlwe 'print for /(...)/' config.xml

-l开关将为您处理换行符,在这种情况下,将换行符添加到打印中。for避免打印空匹配项是必要的。

于 2013-08-21T10:45:30.303 回答
3

在双引号内,一些东西被替换($variable, `command`, ..)。在单引号内时,它们保持原样。

$ echo "$HOME"
/home/falsetru
$ echo '$HOME'
$HOME

$ echo "`echo 1`"
1
$ echo '`echo 1`'
`echo 1`

嵌套引号:

$ echo ""hello""
hello
$ echo '"hello"'
"hello"
$ echo "\"hello\""
"hello"

转义双引号,$以获得相同的结果:

cat config.xml | perl -ne "print \$1,\"\n\" if /([0-9\.]+):161/"
于 2013-08-21T10:05:33.803 回答
2

两件事情:

  1. 嵌套引号。
  2. 变量的扩展方式不同。

第一个命令有一个字符串,恰好包含一些双引号。变量展开。

第二个命令有两个字符串,中间没有引号\n。变量扩展。

假设$1包含“blah”

第一个将此字符串传递给 perl:

print $1,"\n" if /([0-9\.]+):161/

第二个,这个:

print blah,\n if /([0-9\.]+):161/
于 2013-08-21T10:08:41.063 回答