2010-10-03 94 views
7

如何在Perl中实现Unix的grep?我试图用Perl的内置grep。这里是一个不正常的代码:如何在Perl中实现Unix grep?

$pattern = @ARGV[0]; 
$file= @ARGV[1]; 

open($fp,$file); 

@arr = <$fp>; 

@lines = grep $pattern, @arr; 

close($fp); 
print @lines; 

顺便说一下,我想只有基本功能grep不是全功能的,其次我不想做字符串解析自己。我想使用内置grep或Perl的某些功能。

感谢提前:)

回答

13

在Perl引用我们使用@整个阵列。但是要引用单个元素,这是标量,我们使用$

所以,你需要在这些线路上使用$而不是@

$pattern = @ARGV[0]; 
$file= @ARGV[1]; 

而且

@lines = grep $pattern, @arr; 

应该

@lines = grep /$pattern/, @arr; 

在Perl grep具有的一般语法:

grep EXPR,LIST 

它评估EXPR用于LIST每个元素,并返回由该表达式评估为真这些元素的列表值。

EXPR在你的情况下搜索阵列@arr阵列$pattern。若要搜索,则需要使用/PATTERN/而不使用/,则字符串$pattern将被评估为true或false。

+0

- 谢谢明白了。 – TCM 2010-10-03 03:23:40

+2

@coddadict,你做了很大的修复代码中的错误,但这个问题和用户使用的方法将它转换成准'xy问题',所以这是灌输可能不是主题的情况之一。我会建议不要同时阅读整个文件(他希望模拟面向行的grep),我会用grep {}而不是grep()来推荐他,以创建一个好习惯,而三个争论开放。甚至进一步向他展示在线方法(或者逐行的方式)将会是一个加分。 – 2010-10-03 17:11:03

4

基本的“grep”功能已经实现。 (=〜)

$string =~ /pattern/; 
+0

@ user131527: - 谢谢! – TCM 2010-10-03 03:23:22

13

当然,codaddict的答案是正确的,但我想补充一些言论:

use strict; 
use warnings; 

你应该总是与这两条线开始你的脚本

使用三个参数开放和测试错误:

open my $fh, '<', $file or die "unable to open '$file' for reading : $!"; 

而且由于use strict你必须声明所有变量。所以,你的脚本将是这样的:

#!/usr/bin/perl 

use strict; 
use warnings; 

my $pattern = $ARGV[0]; 
my $file = $ARGV[1]; 

open $fh, '<', $file or die "unable to open file '$file' for reading : $!"; 
my @arr = <$fh>; 
close $fh; # close as soon as possible 

my @lines = grep /$pattern/, @arr; 

print @lines; 

如果文件很大,你可以完全避免在内存中读取数据:

#!/usr/bin/perl 
use strict; 
use warnings; 

my $pattern = qr/$ARGV[0]/; 
my $file= $ARGV[1]; 
print "pattern=$pattern\n"; 

my @lines; 
open my $fh, '<', $file or die "unable to open file '$file' for reading : $!"; 
while(my $line=<$fh>) { 
    push @lines, $line if ($line =~ $pattern); 
} 
close($fh); 
print @lines; 
+2

您可以简单地使用'print $ line'替换while循环中的'push @lines,$ line',并避免使用任何数组。如果你的文件是“大的”,那么某个人或某事将不可避免地有一天会触发一个grep,该文件将返回几乎所有的文件行。 (同样大:-) – Randall 2012-02-01 02:58:40

11

您可以直接在命令行近似的grep原始版本。 -e选项允许您在命令行上定义一个Perl脚本。-n选项大致如下所示包装您的脚本:while (<>){ SCRIPT }

perl -ne 'print if /PATTERN/' FILE1 FILE2 ... 

稍好的近似值grep会在每个打印的匹配前加上文件名称的前缀。请注意,这个例子与上面的例子一样,没有经历打开任何文件的麻烦。相反,我们使用Perl的<>结构遍历所有文件,而$ARGV变量提供当前文件名。

use strict; 
use warnings; 

my $pattern = shift; 

while (my $line = <>){ 
    print $ARGV, ':', $line if $line =~ $pattern; 
} 
+1

特殊变量'$ .'包含当前行号。因此,如果你想打印这个,你也可以在perl -ne打印“$ ARGV,$。:$ _”if/PATTERN /'file1 file2'。 – hfs 2013-01-24 14:13:35

13

正如你已经接受一个答案,我写这个答案为未来的读者寻找类似问题的参考,但不完全是你的:

由于人们已经回答了,用模拟的grep的方式perl是使用在线方法。 对于使用Perl作为'更好的'grep(和查找和剪切和...)我建议书minimal perl,你很幸运,因为'perl as a "better" grep'章是其中的一个例子章节。

这里有从书的启发更多的例子:

perl -wnle '/foo/ and print' null.txt # normal grep 
perl -wnle '/foo/ and print "$ARGV: $_"' null.txt # grep -H 
perl -wnle '/foo/ and print $ARGV and close ARGV' null_1.txt null_2.txt # grep -l 

在最后一个例子ARGV是当前文件句柄,并与你-l兴趣与您可以打印文件的匹配查找文件名称并在文件中的第一个匹配之后进入下一个文件。

您也可以通过段落搜索的,而不是行:

$ perl -00 -wnl -e '/\bBRIBE\b/i and print;' SenQ.testimony 
I knew I'd be in trouble if 
I ACCEPTED THE BRIBE! 
So I did not. 

My minimum bribe is $100k, and she only offered me $50k, 
so to preserve my pricing power, I refused it. 

或者只找到了第一场比赛:

$ perl -00 -wnl -e '/\bBRIBE\b/i and close ARGV;' SenQ.testimony 
I knew I would be in trouble if 
I ACCEPTED THE BRIBE! 
So I did not. 

最后,如果你问grep和Perl中,我想大公我应该提及ACK。它在Perl中实现了grep功能并对其进行了扩展。这是一个很棒的工具,作为一个优点,你也可以把它作为一个CPAN包。我一直使用命令行,我不知道你是否可以直接从你的perl程序中访问它的方法,但这会很好。