perl模仿grep -n?

时间:2012-01-14 16:36:42

标签: perl grep

我是perl的新手,想要像这样模仿grep -n:

想:

# egrep -n 'malloc\(|free\(|printf\(' test.c
5:p = malloc(sizeof(char));
6:printf("Test\n");
7:free(p);

有:

# perl grep.pl test.c
malloc\(line 7
free\(line 7
printf(

Processed 10 lines

脚本:

#!/usr/bin/perl
$verbose = 1;
@pattern = ('malloc\(', 'free\(', 'printf(');
$counter = 0;
open(FH, "<", $ARGV[1]) or die;

while (<>) {
  my $matches =  (@pattern[0-2]);
  $counter++;
  # print "line $counter:$_" if ($_ =~ /malloc\(/o);
  print join("line $counter\t\n",@pattern),"\n" if ($_ =~ /$matches/o);
  close (FH);
}
print "\n";
$verbose == 1 && print "Processed $counter lines\n";

不知何故,反击是错误的。我在这里缺少什么?

5 个答案:

答案 0 :(得分:3)

下面是我在windows中grep的基本实现。也许你可以调整它为你工作。

perl中的行号由$.给出(参见perlvar)。使用钻石操作员时,可以简单地按原样打印。但是,如果您使用多个文件,它将不会在文件之间自动重置,您将不得不做一些魔术:

while (<>) {
    # grep and print logic goes here
    # e.g. print "$.: $_" if grep_match();

    close ARGV if eof;  # this will reset $. for each file
}

代码:

use strict;
use warnings;
use v5.10;

my $pattern     = shift;

#use re 'debug';
# Refining the regex to allow using modifiers
$pattern =~ s#^/##;
if ( $pattern =~ s{/([^/]+)$}{} ) {
    $pattern = "(?$1)$pattern";
}

# Windows does not allow globbing, this is the fix
for (@ARGV) {
    unless (-e) {
        @ARGV = win_args(@ARGV);
        last;
    }
}

my $found;
while (<>) {
    if (/$pattern/) {
        unless ($found) {
            say "----- $ARGV -----";
        }
        print;
        $found = 1;
    }
    $found = 0 if eof;
}

sub win_args {
    return map glob, @_;
}

答案 1 :(得分:1)

您的代码存在很多问题,但您应该首先添加

use strict;
use warnings;

该计划的负责人。您必须声明所有变量,但Perl本身将帮助您解决大多数琐碎的问题。

$matches =  (@pattern[0-2]);

相同
$matches =  $pattern[-2];

从数组的末尾访问第二个元素 - 'free(' - 并将其分配给$ matches,这不是你想要的。你可以使用管道运算符匹配任何一个模式,如果你写

$matches = join '|', @pattern;

另外,

print join("line $counter\t\n",@pattern),"\n" if ($_ =~ /$matches/o);

我认为join不符合你的想法。您将第一个字符串作为分隔符加入数组的所有元素。如果您只想要匹配的行,则需要

print "line $counter\t$_\n" if /$matches/o;

这应该让你工作,但正如我所说,你的程序不太理想,我已经展示了必要的最小变化。

答案 2 :(得分:1)

有一个名为$的变量。包含当前行号,因此只输出该变量的值!

perldoc perlvar

答案 3 :(得分:1)

如果这是练习在Perl中编写代码的练习,那么perldoc页面将有助于理解如何使用函数,读取文件以及使用$.等特殊变量。该要求完全符合语言的能力。

如果这是重新发明轮子的尝试,则需要明确规定增值。

如果要在Windows中模拟* nix命令,您对out there already的任何内容感到满意吗?

答案 4 :(得分:-1)

这应该可以解决问题。只需使用文件名选项传递模式(否则使用stdin)

#!/usr/bin/perl

use strict;

my $pattern=shift;
my $fileName=shift;

my $fh;

if ($fileName)
{
   open $fh, $fileName or die "Unable to open file $fileName";
}
else
{
   open $fh, '-';
}

my $lineNumber = 1;
while (<$fh>)
{
   print sprintf("%4d %s", $lineNumber, $_) if (m%$pattern%);
   ++$lineNumber;
}

只需将您的模式构建为(malloc\()|(free\(')|(printf\()