我是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";
不知何故,反击是错误的。我在这里缺少什么?
答案 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\()