Unix Werkzeuge - Grep und verwandte Tools

Übersicht Weiter

»Global search for a regular expression and print out matched lines« - kurz 'g/re/p' ist das gebräuchlichste Kommando, um in Dateien nach bestimmten Mustern zu suchen. Die Grep-Familie umfasst die drei Kommandos egrep, grep und fgrep. Das erste »Extended Grep« (erweitertes grep) versteht »ein paar mehr« der Regulären Ausdrücke als »grep«. »fgrep« (Fixed Grep) hingegen unterstützt nur eine eingeschränkte Teilmenge, womit sich die Suche vor allem in großen Dateien erheblich beschleunigen lässt.

Grep arbeitet bei der Suche wesentlich effizienter als das in einem Editor geschehen würde. Per Voreinstellung schreibt das Kommando alle Zeilen der Eingabe, die das gesuchte Muster enthalten, auf die Standardausgabe. Dabei kann die Eingabe beliebig viele Dateien, als auch die Standardeingabe betreffen. Zudem liefern die Kommandos der Grep-Familie einen Rückgabewert an das Betriebssystem, was sie für die Verwendung in Shellprogrammen bevorzugt.

Der Rückgabewert von Grep Zurück Anfang Weiter

Häufig interessiert man sich nicht für den exakten Inhalt der Zeile, die das Muster enthält, sondern einzig ob das Muster überhaupt existiert. Vor allem in Shellskripten wird man die Ausgaben der Kommandos unterdrücken und anschließend anhand des Rückgabewertes den weiteren Programmablauf steuern.

Rückgabewert 0

Muster wurde gefunden:

# "root" sollte es eigentlich in jeder "passwd" geben
user@sonne> grep root /etc/passwd >& /dev/null
user@sonne> echo $?
0

Rückgabewert 1

Muster wurde nicht gefunden:

# "ROOT" gibt es hoffentlich nicht
user@sonne> grep ROOT /etc/passwd >& /dev/null
user@sonne> echo $?
1

Rückgabewert 2

Datei nicht gefunden:

# die Datei "/bla" gibt es hoffentlich nicht
user@sonne> grep text /bla >& /dev/null
user@sonne> echo $?
2

Wichtige Optionen von Grep Zurück Anfang Weiter

Optionen beeinflussen die Arbeitsweise aller Kommandos der Grep-Familie. Welche Optionen es gibt, beschreibt die folgende Tabelle:

-c

Anzeige der Anzahl Zeilen, in denen das Muster gefunden wurde:

user@sonne> grep -c bash /etc/passwd
38

-i

Groß- und Kleinschreibung werden nicht unterschieden:

user@sonne> grep -i ROot /etc/passwd
root:x:0:0:root:/root:/bin/bash

-l

Nur Anzeige der Namen der Dateien, in denen das Muster gefunden wurde:

user@sonne> grep -l tcp /etc/host*
/etc/hosts.allow
/etc/hosts.deny

-n

Zeigt die Zeilennummer an, in der das Muster gefunden wurde:

user@sonne> grep -n root /etc/passwd
1:root:x:0:0:root:/root:/bin/bash

-s

Unterdrückt die Fehlerausgaben (Standardfehler); sinnvoll in Skripten.

-v

Zeigt alle Zeilen an, die das Muster nicht enthalten:

# ohne diese Option
user@sonne> ps ax | grep inetd
  133 ?        S      0:00 /usr/sbin/inetd
  762 pts/2    S      0:00 grep inetd

# die Ausgabe "grep" herausfiltern
user@sonne> ps ax | grep inetd | grep -v grep
  133 ?        S      0:00 /usr/sbin/inetd

-w

Das Suchmuster muss ein einzelnes Wort sein (also kein Bestandteil eines anderen Wortes).

user@sonne> echo -e "Automaten\n essen\n keine Tomaten" | grep -i Tomaten
Automaten
keine Tomaten

user@sonne> echo -e "Automaten\n essen\n keine Tomaten" | grep -iw Tomaten
keine Tomaten

-A [Anzahl]

Zeigt »Anzahl« Zeilen an, die der Zeile mit dem Muster folgen.

user@sonne> grep -A 2 root /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/bin/bash
daemon:x:2:2:daemon:/sbin:/bin/bash

-B [Anzahl]

Zeigt »Anzahl« Zeilen an, die vor der Zeile mit dem Muster liegen.

Von Grep unterstützte Reguläre Ausdrücke Zurück Anfang Weiter

Nachfolgend sind alle Reguläre Ausdrücke aufgeführt, die die Kommandos der Grep-Familie unterstützen. Hinter jedem Muster ist angegeben, welches grep-Kommando diese Syntax beherrscht. Dabei wird nicht zwischen grep und fgrep unterschieden, da beide Kommandos dieselbe Sprache sprechen (also grep=fgrep).

^ (grep, egrep)

Beginn der Zeile

$ (grep, egrep)

Ende der Zeile

. (grep, egrep)

Genau ein beliebiges Zeichen

* (grep, egrep)

Beliebig viele des vorangegangenen Zeichens

[] (grep, egrep)

Ein Zeichen aus dem Bereich. Anstelle von Zeichen können vordefinierte Klassen von Zeichen verwendet werden: [:alnum:], [:alpha:], [:cntrl:], [:digit:], [:graph:], [:lower:], [:print:], [:punct:], [:space:], [:upper:], und [:xdigit:].

[^] (grep, egrep)

Kein Zeichen aus dem Bereich

\< (grep)

Muster am Wortanfang suchen

\> (grep)

Muster am Wortende suchen

\(..\) (grep)

Eingeschlossenes Muster vormerken; auf dieses kann später über \1 zugegriffen werden. Bis zu neun Muster können auf diese Weise gespeichert werden ( ein Beispiel steht im Abschnitt Reguläre Ausdrücke).

x\{m\} (grep)

m-faches Auftreten des Zeichens x

x\{m,n\} (grep)

mindestens m-, maximal n-maliges Auftreten des Zeichens x

+ (egrep)

Mindestens ein Auftreten des vorangegangenen Zeichens

? (egrep)

Höchstens ein Auftreten des vorangegangenen Zeichens

x|y (egrep)

Zeichen "x" oder Zeichen "y"

(abc|xyz) (egrep)

Zeichenkette "abc" oder Zeichenkette "xyz". Die runden Klammern können entfallen.

Grep - Beispiele Zurück Anfang Weiter

Einfache Beispiele zur Anwendung von grep begegneten uns schon an mehreren Stellen dieses Buches. Nun möchte ich versuchen, anhand typischer Anforderungen bei der alltäglichen Arbeit mit einem Unix-System, die Verwendung der komplexeren Mechanismen zu erläutern.

Beispiel 1

Bei der Systemadministration fragt man sich häufig, in welcher Datei eigentlich welche Shell-Variable gesetzt wird? Die globalen Vorgaben erfolgen zum Großteil in den Dateien des Verzeichnisses /etc. Also interessieren uns die Namen der Dateien, in denen z.B. die PATH-Variable modifiziert wird:

user@sonne> grep -l PATH /etc/* 2>/dev/null
/etc/csh.cshrc
/etc/login.defs
/etc/manpath.config
/etc/profile
/etc/profile.rpmsave
/etc/rc.config
/etc/squid.conf

Die Umleitung der Fehlerausgabe nach /dev/null ist sinnvoll, da »grep« nicht auf Verzeichnisse anwendbar ist.

Beispiel 2

Wie viele Nutzer sind Mitglied in der default-Gruppe users (GID 100)?

user@sonne> grep -c ':[0-9]\{1,\}:100:' /etc/passwd
9

Bei der Angabe des Suchmusters hilft uns die Kenntnis des Aufbaus der Datei »/etc/passwd«. Dabei steht die GruppenID immer zwischen zwei Doppelpunkten. Allerdings könnte es sein, dass auch die NutzerID (UID) 100 vergeben ist - der Ausdruck :[0-9]\{1,\}:100: garantiert, dass :100: das zweite rein numerische Feld betrifft. Eine andere Schreibweise ist:

user@sonne> grep -c ':[[:digit:]]\{1,\}:100:' /etc/passwd
9


Beispiel 3

Welche Netzwerkdienste über UDP sind auf unserem System verfügbar (Datei /etc/inetd.conf)?

user@sonne> grep '^[^#].*[[:space:]]udp' /etc/inetd.conf
 time    dgram   udp     wait    root    internal
 talk    dgram   udp     wait    root    /usr/sbin/tcpd  in.talkd
 ntalk   dgram   udp     wait    root    /usr/sbin/tcpd  in.talkd
 netbios-ns      dgram   udp     wait    root    /usr/sbin/nmbd  nmbd

Jede Zeile, die mit einem # beginnt, ist ein Kommentar. Also filtern wir solche Zeilen aus (^[^#]). Das gesuchte Protokoll ist "udp". Vor diesem Schlüsselwort können beliebig viele Zeichen (.*) gefolgt von einem Leerzeichen oder Tabulator ([[:space:]]) stehen.

Beispiel 4

Je gezielter man nach Informationen fahndet, desto verwirrender wird die Angabe der Suchmusters. In zahlreichen Fällen wird die Verwendung von Pipes einleuchtender sein. Das Ergebnis aus obigen Beispiel erhält man auch mit folgender Befehlsfolge:

user@sonne> grep -w udp /etc/inetd.conf | grep -v ^#
 time    dgram   udp     wait    root    internal
 talk    dgram   udp     wait    root    /usr/sbin/tcpd  in.talkd
 ntalk   dgram   udp     wait    root    /usr/sbin/tcpd  in.talkd
 netbios-ns     dgram   udp     wait    root    /usr/sbin/nmbd  nmbd

Egrep - Beispiele Zurück Anfang Weiter

Egrep ist hilfreich, wenn Sie nach Zeilen in der Eingabe suchen, die mindestens eine von mehreren Zeichenketten enthalten.
So findet das folgende Beispiel alle Zeilen der Datei /etc/fstab, in denen »floppy« und »cdrom« auftauchen:

user@sonne> egrep 'floppy|cdrom' /etc/fstab
/dev/hdc    /cdrom         iso9660   ro,noauto,user,exec 0   0
/dev/fd0    /floppy        auto      noauto,user         0   0

Eine weitere interessante Anwendung ist die Suche nach »geteilten« Mustern, d.h. die bekannten Teile stehen auf einer Zeile, aber der Zwischenraum ist unbekannt. Zur Demonstration dient folgende Datei:

user@sonne> cat beispiel.txt
1 ein  Zwischenraum
2 ein           Zwischenraum
3 ein    Zwischenraum
4 ein           Zwischenraum

Gesucht werden sollen alle Zeilen, die »einen Zwischenraum« enthalten; jedoch ist die Zusammensetzung des Zwischenraums nicht bekannt (und besteht teils aus Leerzeichen, teils aus Tabulatoren und teils aus beidem). Mit dem normalen grep könnte man sich mit folgendem Konstrukt behelfen:

user@sonne> grep "ein[[:space:]][[:space:]]*Zwischenraum" beispiel.txt
1 ein  Zwischenraum
2 ein           Zwischenraum
3 ein    Zwischenraum
4 ein           Zwischenraum

Die doppelte Anwendung des [:space:]-Musters ist für diesen Fall notwendiger Ballast, da wir ja mindestens einen Zwischenraum benötigen. Eleganter ist da die Möglichkeit von "+" in Verbindung mit egrep:

user@sonne> egrep "ein[[:space:]]+Zwischenraum" beispiel.txt
1 ein  Zwischenraum
2 ein           Zwischenraum
3 ein    Zwischenraum
4 ein           Zwischenraum

Fgrep - Beispiele Zurück Anfang

Fgrep kann immer anstelle von grep verwendet werden, falls das zu suchende Muster keine regulären Ausdrücke enthält. Alle Sonderzeichen in der Musterzeichenkette verlieren ihre Sonderbedeutung und werden als Bestandteil des Musters verstanden. Fgrep arbeitet dadurch etwas schneller als grep und ist vor allem beim Durchsuchen großer Datenmengen nützlich.