为什么这两个命令的输出不同?
cat config.xml|perl -ne 'print $1,"\n" if /([0-9\.]+):161/'
cat config.xml|perl -ne "print $1,"\n" if /([0-9\.]+):161/"
首先按预期打印出匹配组,而秒打印整行。
答案 0 :(得分: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 /.../
这意味着\n
不再是print
的参数,它是print
之后的语句,它位于void上下文中,因此会被忽略。我们可以通过这个警告(我必须在我的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 (Useless Use of Cat)。在命令行上使用-n
开关时,可以为perl指定文件参数。其次,您不需要为此使用变量,只需打印正则表达式的返回值:
perl -nlwe 'print for /(...)/' config.xml
-l
开关将为您处理换行符,并在这种情况下为打印添加换行符。 for
是避免打印空匹配所必需的。
答案 1 :(得分: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/"
答案 2 :(得分:2)
两件事:
第一个命令有一个恰好包含一些双引号的字符串。变量不展开。
第二个命令有两个字符串,其间有一个不带引号的\n
。变量 已扩展。
我们说$1
包含“blah”
第一个将此字符串传递给perl:
print $1,"\n" if /([0-9\.]+):161/
第二个,这个:
print blah,\n if /([0-9\.]+):161/