简体   繁体   English

如何在Perl中实现Unix grep?

[英]How can I implement Unix grep in Perl?

How can I implement grep of Unix in Perl? 如何在Perl中实现Unix的grep I tried to use Perl's built-in grep . 我尝试使用Perl的内置grep Here is the code which is not working: 这是不起作用的代码:

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

open($fp,$file);

@arr = <$fp>;

@lines = grep $pattern, @arr;

close($fp);
print @lines;

And by the way, i am trying only basic grep functionality not full featured and secondly i don't want to do string parsing myself. 顺便说一句,我只尝试基本的grep功能不完整功能,其次我不想自己进行字符串解析。 I want to use inbuilt grep or some function of Perl. 我想使用内置的grep或Perl的一些功能。

Thanks in advance :) 提前致谢 :)

As you already accepted an answer, I am writing this answer for reference for future readers searching for similar problems, but not exactly yours: 正如您已经接受了答案,我正在编写此答案以供将来读者搜索类似问题的参考,但不完全是您的:

As people have answered already, the way of simulating grep with perl is to use the online approach. 正如人们已经回答的那样,使用perl模拟grep的方法是使用在线方法。 For the use of perl as a 'better' grep (and find and cut and...) I recomend the book minimal perl and you are lucky because the chapter for 'perl as a "better" grep' is one of the sample chapters. 对于使用perl作为'更好'的grep(以及查找和剪切......),我推荐本书最小的perl ,你很幸运,因为'perl as a“grep'这一章是示例章节之一。

Here you have more examples inspired from the book: 这里有更多来自本书的例子:

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

In the last example ARGV is the current filehandle, and as with -l you are interested in finding files with the match you can print the file name and go for the next file after the first match in a file. 在最后一个示例中,ARGV是当前文件句柄,与-l一样,您有兴趣查找具有匹配项的文件,您可以打印文件名,并在文件中第一次匹配后转到下一个文件。

Also you can search by paragraph instead by line: 您也可以逐行搜索:

$ 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.

Or find only the first match: 或者只找到第一场比赛:

$ 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.

And finally if you ask about grep and perl, I think thay I should mention ACK . 最后,如果你问grep和perl,我想我应该提一下ACK It implements, in perl, the grep functionality and extend it. 它在perl中实现了grep功能并对其进行了扩展。 This is a wonderful tool and as a plus you can have it also as a CPAN package. 这是一个很棒的工具,作为一个加分,你可以把它作为一个CPAN包。 I have always use as a command line, I don't know if you can access its methods directly from your perl programs but this would be very nice. 我总是使用命令行,我不知道你是否可以直接从你的perl程序访问它的方法,但这将是非常好的。

In Perl to refer an entire array we use @ . 在Perl中引用整个数组我们使用@ But to refer the individual elements, which are scalar we use $ . 但是要引用标量的各个元素,我们使用$

So, you need to use $ and not @ on these lines: 所以,你需要在这些行上使用$而不是@

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

Also

this 这个

@lines = grep $pattern, @arr;

should be 应该

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

the grep in Perl has the general syntax of: Perl中的grep具有以下一般语法:

grep EXPR,LIST

It evaluates the EXPR for each element of LIST and returns the list value consisting of those elements for which the expression evaluated to true. 它评估LIST每个元素的EXPR ,并返回由表达式求值为true的元素组成的列表值。

The EXPR in your case is searching for the pattern $pattern in array @arr . 您的案例中的EXPR正在搜索数组@arr的模式$pattern To search you need to use the /PATTERN/ without the / the string $pattern will be evaluated for true or false. 要搜索,您需要使用/PATTERN/而不使用/字符串$pattern将被评估为true或false。

Of course, codaddict's answer is right, but i'd like to add some remarks : 当然,codaddict的回答是正确的,但我想补充一些评论:

You should always begin your scripts with these two lines : 您应该始终使用以下两行开始脚本:

use strict;
use warnings;

Use three args open and test for errors: 使用三个args打开并测试错误:

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

And because of use strict you have to declare all variables. 而且由于use strict你必须声明所有变量。 So your script will be like: 所以你的脚本将是这样的:

#!/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;

If your file is large, you can avoid read it entirely in memory: 如果您的文件很大,您可以避免在内存中完全读取它:

#!/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;

You can approximate a primitive version of grep directly on the command line. 您可以直接在命令行上逼近grep的原始版本。 The -e option allows you to define a Perl script on the command line. -e选项允许您在命令行上定义Perl脚本。 The -n option wraps your script roughly like this: while (<>){ SCRIPT } . -n选项大致包装你的脚本: while (<>){ SCRIPT }

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

A slightly better approximation of grep would prefix the file name in front of each printed match. 稍微好一点的grep将在每个打印的匹配前面添加文件名前缀。 Note that this example, like the one above, does not go through the hassle of opening any files. 请注意,此示例与上面的示例一样,不会经历打开任何文件的麻烦。 Instead we use Perl's <> construct to iterate through all of the files, and the $ARGV variable provides the current file name. 相反,我们使用Perl的<>构造来遍历所有文件, $ARGV变量提供当前文件名。

use strict;
use warnings;

my $pattern = shift;

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

The basic "grep" functionality is already implemented. 基本的“grep”功能已经实现。 (=~) (=〜)

$string =~ /pattern/;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM