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

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

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

open($fp,$file);

@arr = <$fp>;

@lines = grep $pattern, @arr;

close($fp);
print @lines;

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

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

Ответы на вопрос(5)

ответ 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;
 Randall01 февр. 2012 г., 03:58
Вы можете заменить 'push @lines, $ line' в цикле while просто на 'print $ line' и избежать использования каких-либо массивов. Если ваш файл «большой», то кто-то или что-то неизбежно однажды вызовет grep, который возвращает почти все строки файла. (и одинаково большой :-)

Вы можете приблизить примитивную версиюgrep прямо в командной строке.-e Опция позволяет вам определить скрипт Perl в командной строке.-n опция оборачивает ваш скрипт примерно так:while (<>){ SCRIPT }.

perl -ne 'print if /PATTERN/' FILE1 FILE2 ...

Немного лучшее приближениеgrep будет префикс имени файла перед каждым напечатанным соответствием. Обратите внимание, что в этом примере, как и в приведенном выше примере, нет необходимости открывать какие-либо файлы. Вместо этого мы используем Perl's<> построить, чтобы перебрать все файлы, и$ARGV переменная предоставляет текущее имя файла.

use strict;
use warnings;

my $pattern = shift;

while (my $line = <>){
    print $ARGV, ':', $line if $line =~ $pattern;
}
 hfs24 янв. 2013 г., 15:13
Специальная переменная$. содержит номер текущей строки Так что, если вы хотите напечатать это тоже, вы могли бы сделатьperl -ne 'print "$ARGV,$.:$_" if /PATTERN/' file1 file2.
Решение Вопроса

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

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

$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 будет оцениваться как истина или ложь.

 TCM03 окт. 2010 г., 05:23
- Спасибо, получил его.
 Pablo Marin-Garcia03 окт. 2010 г., 19:11
@coddadict, вы здорово исправили ошибки в коде, но этот вопрос и подход, использованный пользователем, превращают его в квази-xy-проблему, так что это одна из тех ситуаций, когда идеологическая обработка, вероятно, не является не по теме. Я бы порекомендовал не читать весь файл одновременно (он хотел имитировать grep, ориентированный на строки), я бы порекомендовал ему использовать grep {} вместо grep () просто для создания хорошей привычки, и три аргументы открыты. И даже дальнейшая демонстрация ему онлайн-подхода (или, альтернативно, строка за строкой) была бы плюсом.

grep" уже реализована. (= ~)

$string =~ /pattern/;
 TCM03 окт. 2010 г., 05:23
@ user131527: - Спасибо!

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

Как уже отвечали люди, способ симуляции 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-программ, но это было бы очень хорошо.

 Pablo Marin-Garcia19 июн. 2019 г., 12:06
@ волк да, соответственно обновил ответ

Ваш ответ на вопрос