2010-10-03 9 views
7

Wie kann ich grep von Unix in Perl implementieren? Ich habe versucht, Perls eingebautes grep zu verwenden. Hier ist der Code, der nicht funktioniert:Wie kann ich Unix Grep in Perl implementieren?

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

open($fp,$file); 

@arr = <$fp>; 

@lines = grep $pattern, @arr; 

close($fp); 
print @lines; 

Und übrigens, ich versuche nur grundlegende grep Funktionalität nicht voll funktionsfähige und zweitens will ich nicht Zeichenfolge selbst tun Parsen. Ich möchte eingebaute grep oder eine Funktion von Perl verwenden.

Vielen Dank im Voraus :)

Antwort

13

In Perl ein ganzes Array wir @ verwenden verweisen. Aber um die einzelnen Elemente zu bezeichnen, die skalar sind, verwenden wir $.

So müssen Sie $ und nicht @ auf diesen Linien verwenden:

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

Auch

diese

@lines = grep $pattern, @arr; 

sollte

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

die grep in Perl hat die allgemeine Syntax:

grep EXPR,LIST 

es die EXPR für jedes Element von LIST auswertet und gibt den Wert Liste dieser Elemente besteht, für die der Ausdruck wahr bewertet.

Die EXPR in Ihrem Fall sucht nach dem Muster $pattern in Array @arr. Um zu suchen, müssen Sie die /PATTERN/ ohne die / die Zeichenfolge $pattern wird für wahr oder falsch ausgewertet werden.

+0

- Vielen Dank. – TCM

+2

@coddadict, du hast es großartig gemacht, die Bugs im Code zu beheben, aber diese Frage und der vom Benutzer verwendete Ansatz konvertiert es in ein quasi 'xy-Problem', also ist dies eine dieser Situationen, dass Indoktrination wahrscheinlich nicht vom Thema abweicht. Ich hätte empfohlen, nicht die ganze Datei zur gleichen Zeit zu lesen (er wollte grep simulieren, das linienorientiert ist), ich hätte ihn mit dem grep {} anstelle des grep() empfohlen, nur um eine gute Angewohnheit zu schaffen, und die drei Argumente öffnen. Und es wäre noch ein Plus gewesen, ihm den Online-Ansatz (oder alternativ die Zeile für Zeile mit while) noch weiter zu zeigen. –

4

Die grundlegende "grep" -Funktionalität ist bereits implementiert. (= ~)

$string =~ /pattern/; 
+0

@ user131527: - Vielen Dank! – TCM

13

Natürlich Antwort des codaddict ist richtig, aber ich möchte einige Bemerkungen hinzufügen:

Sie sollten immer Ihre Skripte mit diesen beiden Zeilen beginnen:

use strict; 
use warnings; 

Verwenden drei args offen und Test für Fehler:

open my $fh, '<', $file or die "unable to open '$file' for reading : $!"; 

und wegen use strict haben Sie deklariere alle Variablen. So Ihr Skript wie:

#!/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; 

Wenn die Datei groß ist, können Sie es vollständig im Speicher vermeiden lesen:

#!/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; 
+2

Sie können die 'push @lines, $ line' in der while-Schleife einfach mit 'print $ line' ersetzen und keine Arrays verwenden. Wenn Ihre Datei "groß" ist, wird unweigerlich jemand oder etwas eines Tages ein Grep auslösen, das fast alle Zeilen der Datei zurückgibt. (und gleich groß :-) – Randall

11

Sie können eine primitive Version von grep direkt auf der Kommandozeile nähern. Mit der Option -e können Sie ein Perl-Skript in der Befehlszeile definieren.Die -n Option umschließt Ihr Skript grob wie folgt: while (<>){ SCRIPT }.

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

eine etwas bessere Annäherung der grep würde den Dateinamen vor jedem gedruckten Spiel voranstellen. Beachten Sie, dass dieses Beispiel, wie das oben genannte, nicht die Mühe macht, Dateien zu öffnen. Stattdessen verwenden wir das Konstrukt <> von Perl, um alle Dateien zu durchlaufen, und die Variable $ARGV liefert den aktuellen Dateinamen.

use strict; 
use warnings; 

my $pattern = shift; 

while (my $line = <>){ 
    print $ARGV, ':', $line if $line =~ $pattern; 
} 
+1

Die Sondervariable '$ .' enthält die aktuelle Zeilennummer. Also, wenn Sie das auch drucken möchten, könnten Sie 'perl -ne 'drucken" $ ARGV, $.: $ _ "Wenn/PATTERN /' file1 file2'. – hfs

13

Wie Sie bereits eine Antwort akzeptiert, ich schreibe diese Antwort als Referenz für zukünftige Leser für ähnliche Probleme suchen, aber nicht genau Sie:

Da die Menschen bereits beantwortet haben, die Art und Weise grep die Simulation mit Perl soll den Online-Ansatz nutzen. Für die Verwendung von Perl als 'besseres' Grep (und finden und schneiden und ...) Ich empfehle das Buch minimal perl und Sie haben Glück, denn das Kapitel für 'perl as a "better" grep' ist eines der Beispielkapitel.

Hier haben Sie weitere Beispiele aus dem Buch inspiriert:

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 

Im letzten Beispiel ARGV ist die aktuelle Dateihandle, und wie bei -l sind Sie interessieren Dateien mit dem Spiel finden Sie die Datei drucken benennen Sie und gehen Sie nach der ersten Übereinstimmung in einer Datei für die nächste Datei.

Sie können auch nach Absatz stattdessen für Zeile suchen:

$ 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. 

Oder nur das erste Spiel finden:

$ 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. 

Und schließlich, wenn Sie über grep und Perl fragen, ich glaube, Thay ich sollte Erwähnen Sie ACK. Es implementiert in Perl die grep-Funktionalität und erweitert sie. Dies ist ein wunderbares Werkzeug und als ein Plus können Sie es auch als CPAN-Paket haben. Ich benutze immer als Befehlszeile, ich weiß nicht, ob Sie ihre Methoden direkt von Ihren Perl-Programmen zugreifen können, aber das wäre sehr nett.