Как я могу реализовать Unix grep в Perl? - PullRequest
8 голосов
/ 03 октября 2010

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

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

open($fp,$file);

@arr = <$fp>;

@lines = grep $pattern, @arr;

close($fp);
print @lines;

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

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

Ответы [ 5 ]

14 голосов
/ 03 октября 2010

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

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

13 голосов
/ 03 октября 2010

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

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

use strict;
use warnings;

Используйте три аргументаоткройте и проверьте на ошибки:

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;
13 голосов
/ 03 октября 2010

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

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

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

Также

это

@lines = grep $pattern, @arr;

должно быть

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

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

grep EXPR,LIST

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

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

11 голосов
/ 03 октября 2010

Вы можете аппроксимировать примитивную версию grep непосредственно в командной строке. Опция -e позволяет вам определять Perl-скрипт в командной строке. Опция -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;
}
4 голосов
/ 03 октября 2010

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

$string =~ /pattern/;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...