Alexander (HH): grep Rückgabewert

Beitrag lesen

Bist Du Dir übrigens bewußt, das bei den meisten grep-Implementationen der Punkt eine besondere Bedeutung hat?

Alexander

Hi

wäre das dann in etwa die Alternative?

foreach my $filename (glob("$ZONE/*")) {
open (READ,$filename) or die "$!";
@bar=<READ>;
print grep(/133.8.165.2/, @bar);

wobei ich ja true oder false benötige und nicht den output;

close (READ) or die "$!";
}

So in der Art. Den Dateinamen solltest Du noch in die die()s mit reinnehmen, "Permission denied" bei 200 Dateien ist nicht wirklich hilfreich. ;-)

ABER: /133.8.165.2/ matcht auch 713398716529, sogar 133k8165W201, was in Deinem (vermutlichen) Anwendungsfall aber schlimmer ist: Es matcht 133.8.165.20 bis 133.8.165.29 und 133.8.165.200 bis 133.8.165.255. Das macht das eigenständige grep-Programm übrigens auch. Bitte informiere Dich anhand der Perl-Dokumentation über die Besonderheiten des Punkts in Regular Expressions. Außerdem suchst Du, je nach genauem Dateiformat, einen Zeilenanfang, ein Zeilenende, Leerzeichen oder ähnliche Trennzeichen.

Wenn Du von Perls grep nur wissen willst, ob es einen oder mehrere Treffer gibt, nutze es in einem boolschen Kontext, sprich:

if (grep /irgendwas/,@liste) {
  print "gefunden!\n";
} else {
  print "nix da!\n";
}

Nachteil von grep, egal ob extern oder in Perl eingebaut: Es geht immer über die GESAMTE Liste/Datei/Array, auch wenn Dir die Aussage "mindestens ein Treffer gefunden" reicht.

Besonders schlimm in Deinem Beispiel: Du ziehst die Dateien jeweils vollständig in den Speicher, nur um sie einmal durch grep durchlaufen zu lassen. if (grep /pattern/,<FILE>) könnte Perl vielleicht noch optimieren, so das immer nur eine Zeile in den Speicher gezogen wird, aber Dein Beispiel verhindert eine solche Optimierung. Zum Killer wird das besonders dann, wenn Deine Dateien viele Zeilen enthält, den jeder String in Perl enthält unsichtbar, aber im Speicherverbrauch erkennbar, noch etliche Bytes an Verwaltungsinformationen. Bei einer Log-Datei à la Apache kommen da leicht mal ein paar Megabyte nur an Verwaltungsdaten zusammen.

Ich würde Dir raten, die Datei "von Hand" zeilenweise zu lesen und beim ersten Treffer sofort abzubrechen.

use IO::File;
sub hasPattern
{
  my $fn=shift;
  my $f=IO::File->new($fn,'<') or die "$fn: $!";
  local $_; # nicht $_ des Aufrufers verändern!
  while (<$f>) {
    return 1 if /pattern/; # (1)
  }
  $f->close(); # (2)
  return; # (3)
}

print "$filename\n" if hasPattern($filename);

IO::File hat hier gegenüber dem normalen open einen Riesenvorteil: Sobald das Programm aus dem Scope, in dem die Variable mit dem IO::File-Objekt definiert ist, läuft, wird die durch IO::File repräsentierte Datei automatisch geschlossen. Das passiert bei (1), und da nach (2) die Funktion auch gleich beendet ist, ist (2) prinzipiell überflüssig. Es ist aber guter Stil, die Datei so bald wie möglich zu schließen, denn Datei-Handles gibt es nicht in unbegrenzter Menge.

(3): return ohne alles am Ende liefert false in *jedem* Kontext. return 0, return '' oder return undef würde im List-Kontext *true* ergeben.

Oder hast du mal ein Beispiel

Nur Fragmente, wenn Du eine vollständige Lösung von mir haben möchtest, fällt das unter kostenpflichtige Arbeit.

Alexander