Как реализовать Unix grep в Perl?

как я могу реализовать grep Unix в Perl? Я попытался использовать встроенный Perl grep. Вот код, который не работает:

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

open($fp,$file);

@arr = <$fp>;

@lines = grep $pattern, @arr;

close($fp);
print @lines;

и, кстати, я пытаюсь только basic grep функциональность не полнофункциональная, а во-вторых, я не хочу делать разбор строк сам. Я хочу использовать встроенный grep или некоторая функция Perl.

спасибо заранее :)

5 ответов


в Perl для ссылки на весь массив мы используем @. Но для обозначения отдельных элементов, которые являются скалярными мы используем $.

Итак, вам нужно использовать $, а не @ на эти строки:

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

и

этой

@lines = grep $pattern, @arr;

должно быть

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

the grep в Perl имеет общий синтаксис:

grep EXPR,LIST

он оценивает в EXPR для каждого элемента LIST и возвращает значение списка, состоящее из тех элементов, для которых выражение оценивается как true.

на EXPR в вашем случае-это поиск шаблона $pattern в массиве @arr. Для поиска вам нужно использовать /PATTERN/ без / строка $pattern будет оцениваться как true или false.


конечно, ответ codaddict правильный, но я хотел бы добавить несколько замечаний:

вы всегда должны начинать свои скрипты с этих двух строк:

use strict;
use warnings;

используйте три args открыть и проверить на наличие ошибок:

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;

как вы уже приняли ответ, я пишу этот ответ Для справки для будущих читателей, ищущих подобные проблемы, но не совсем ваши:

как люди уже ответили, способ моделирования grep с perl заключается в использовании онлайн-подхода. Для использования perl в качестве "лучшего" grep (и найти, и вырезать и...) Рекомендую книгу минимальный perl и вам повезло, потому что глава 'perl как" лучший "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 0k, and she only offered me k,
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 и Перл, я думаю, что я должен упомянуть ACK. Он реализует в perl функциональность grep и расширяет ее. Это замечательный инструмент, и в качестве плюса вы можете иметь его также как пакет CPAN. Я всегда использую командную строку, я не знаю, можете ли вы получить доступ к ее методам непосредственно из ваших программ perl, но это было бы очень приятно.


вы можете приблизиться к примитивной версии grep непосредственно в командной строке. The -e опция позволяет определить скрипт Perl в командной строке. The -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;
}

базовая функциональность "grep" уже реализована. (=~)

$string =~ /pattern/;