Re: regex fuer zwei Begriffe mit UND Verknuepfung

From: Oliver Fromme <olli(at)lurza.secnetix.de>
Date: Sat, 11 Feb 2006 13:59:21 +0100 (CET)

Marc Santhoff <M.Santhoff(at)t-online.de> wrote:
> Oliver Fromme wrote:
> > Du möchtest also aus einer Reihe von Dokumenten diejenigen
> > heraussuchen, die zwei bestimmte Begriffe enthalten, und
> > zwar nicht zwangsläufig in derselben Zeile. Das geht so:
> >
> > grep -l Begriff1 *.txt | xargs grep -l Begriff2
> >
> > Das liefert die Die betreffenden Dateinamen.
>
> Genau an sowas hatte ich gedacht. Ggf. noch mit "find" vorweg.

Ja, das kommt dann auf diverse Dinge an.

Ich erlaube mir mal einen kleinen Shell-Exkurs. :-)

Erstens kommt es darauf an, wieviele Dateien es sind (oder
sein können). Wenn es extrem viele sein können, könnte die
Grenze von execve() gesprengt werden. Diese Grenze kann
man per »sysctl kern.argmax« abfragen; in 4.x und 5.x ist
sie 64 kbyte groß, in 6.x beträgt sie 256 kbyte, aber man
sollte besser keine Annahmen darüber machen, insbesondere
nicht in Shell-Skripten. Wird die Grenze erreicht, liefert
die Shell bei »grep ... *« u.ä. eine Fehlermeldung wie
»Argument list too long«. Wenn dieser Fall auftreten kann,
nimmt man anstelle von

   grep ... *.txt

besser:

   echo *.txt | xargs grep ...

Da »echo« ein Shell-builtin ist, unterliegt er nicht dem
execve()-Limit, und xargs(1) sorgt dann dafür, daß die Ar-
gumente in verdauliche Happen aufgeteilt werden. Man kann
natürlich auch find(1) hernehmen (ebenfalls mit xargs),
wobei man dann »-maxdepth 1« angeben muß, falls man nicht
rekursiv suchen möchte. Im allgemeinen ist in dem Fall
aber echo einfacher und schneller als find.

Womit wir schon beim zweiten Punkt wären: ob man rekursiv
in einem ganzen Verzeichnisbaum suchen möchte oder nicht.
Bei rekursiver Suche muß man im allgemeinen natürlich schon
find(1) hernehmen, z.B.

   find . -type f -name '*.txt' | xargs grep ...

oder:

   find . -type f | grep '\.txt$' | xargs grep ...

Drittens hängt es auch von den Fähigkeiten der Shell ab.
Da ich die zsh verwende, die bereits rekursives Globbing
und Filtern nach Dateitypen unterstützt (und diverse ande-
re Dinge), brauche ich in vielen Fällen gar kein find(1).
Obiges kann man in zsh auch einfach so machen:

   echo **/*(.) | xargs grep ...

Das doppelte Sternchen »**« bedeutet rekursive Suche und
wird zu allen Unterverzeichnissen expandiert. Der ange-
hängte Punkt in Klammern »(.)« bedeutet, daß nur Dateien
expandiert werden sollen (entspricht »-type f« bei find).
Wenn ich weiß, daß das execve()-Limit nicht überschritten
werden kann, geht's natürlich noch einfacher:

   grep ... **/*(.)

Wie gesagt, das ist ein spezielles zsh-Feature. Für por-
table Shell-Skripte muß ich natürlich auch wieder auf
find(1) zurückgreifen.

> > Mir ist kein
> > GUI-Programm bekannt, das derartiges leistet; zumindest
> > ist keines per default mit einem der gängigen GUIs (KDE,
> > Gnome, Windows) installiert.
>
> Nein, dafür gibt es kein GUI. Aber auch als Konsolbefehl ist es nicht so
> besonders intuitiv.

Hm. Ich finde es eigentlich schon recht intuitiv.

> Schließlich wäre es für grep kein problem, den Text
> statt mit nur einem gleich mit zwei Begriffen zu vergleichen,

Das ist der Denkfehler: grep vergleicht nicht »den Text«,
sondern arbeitet zeilenweise. Das steht auch gleich so im
allerersten Absatz in der manpage. Und man _kann_ mit
grep natürlich problemlos nach zwei Begriffen suchen -- so-
fern sie in derselben Zeile stehen.

Man könnte natürlich ein Tool schreiben, das jeweils den
gesamten Text einer Datei als eine Einheit zum Vergleichen
betrachtet und die Zeilenumbrüche ignoriert. Das wäre dann
aber kein grep, und etwa die Hälfte der grep-Optionen würde
in so einem Tool nicht funktionieren bzw. keinen Sinn erge-
ben (z.B. die Optionen -A, -B, -C, -b, -c, -n und -v).

Andererseits würde niemand so ein Tool schreiben, weil die
Aufgabe ja bereits recht einfach mit vorhandenen Mitteln
lösbar ist, indem man vorhandene Tools kombiniert, was ja
eine der Stärken und grundlegenden Designkonzepte von UNIX
ist. Zur Bequemlichkeit könnte man sowas in ein triviales
Shell-Skript verpacken, das man z.B. »mgrep« (multi-grep)
oder so nennen könnte.

Gruß
   Olli

-- 
Oliver Fromme,  secnetix GmbH & Co. KG, Marktplatz 29, 85567 Grafing
Dienstleistungen mit Schwerpunkt FreeBSD: http://www.secnetix.de/bsd
Any opinions expressed in this message may be personal to the author
and may not necessarily reflect the opinions of secnetix in any way.
"File names are infinite in length, where infinity is set to 255 characters."
        -- Peter Collinson, "The Unix File System"
To Unsubscribe: send mail to majordomo(at)de.FreeBSD.org
with "unsubscribe de-bsd-questions" in the body of the message
Received on Sat 11 Feb 2006 - 14:00:41 CET

search this site