2012-01-14 3 views
0

Я новичок в PERL и хотят подражать Grep -n, как это:perl emulate 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"; 

Как-то счетчик ошибочен. Что мне здесь не хватает?

+3

Что делает 'close (FH)' в этом цикле? – Mat

+1

И что с 'open (FH," <", $ ARGV [1])' в первую очередь, учитывая, что чтение выполняется с '<>', а не ''? –

+1

Почему downvotes? Вопрос недвусмыслен, и было показано усилие. Единственное, что я хочу знать, - это то, почему OP хочет сделать это в первую очередь. – Zaid

ответ

-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\()

+0

nice :) Спасибо всем! Этот выглядит очень чистым. Извините за шансы. – Juergen

+0

Вы могли бы дать мне точку за это! (и, возможно, галочка!) –

+0

Регулярное выражение не будет компилироваться - вам нужно избежать скобки после «printf». Также вы не ответили на вопрос, почему программа OP не работает. – Borodin

1

Существует много плохой код, но вы должны начать с добавлением

use strict; 
use warnings; 

во главе программы. Вам придется объявить все ваши переменные, но сам Perl поможет вам решить самые простые проблемы.

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

такая же, как

$matches = $pattern[-2]; 

, который обращается второй элемент из конца массива - «свободный (» - и присваивает его $ спичек, которые не то, что вы хотите вас. может использовать оператор трубы, который соответствует любому из выбора моделей, если вы пишете

$matches = join '|', @pattern; 

Кроме того, в

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

Не думаю join делает то, что вы думаете, что делает. Вы объединяете все элементы массива с первой строкой в ​​качестве разделителя. Если вы просто хотите, совпадающую линию, то вам нужно

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

Это должно заставить вас работать, но, как я говорю, ваша программа меньше, чем идеал, и я показал минимальные изменения необходимы.

1

Существует переменная с именем $. который содержит текущий номер строки, поэтому просто выведите значение этой переменной!

perldoc perlvar 
3

Ниже приведена моя рудиментарная реализация 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

Если это чтобы получить представление о кодировании в Perl, страницы perldoc будут полезны для понимания того, как используются функции, считываются файлы и используются специальные переменные, такие как $.. Это требование хорошо соответствует возможностям языка.

Если это попытка изобретать велосипед, необходимо добавить четкую структуру добавленной стоимости.

Если это делается для эмуляции команды * nix в Windows, вы не удовлетворены тем, что есть out there already?.

+0

+1 Я никогда не знал, что в окнах была команда« findstr ». – TLP