Bash-Befehle und Bash-Programmierung
© Klaus Gerhardt, 08.2005
(Copyright, Nutzungsbedingungen, Haftungsausschluss, s.u.)
grep gibt Zeilen aus, die einem Suchmuster entsprechen
Reguläre Ausdrücke (regular expressions)
Die Praxis, Reguläre Ausdrücke in der Anwendung mit grep
grep mit find kombinieren
zgrep sucht in komprimierten Dateien
Syntax:
grep [Optionen] Muster Datei1 [Datei2] ... [DateiN]
grep [Optionen] -e Muster1 -e Muster2 ... [-e MusterN] Datei1 [Datei2] ... [DateiN]
grep sucht in den angegebenen Dateien nach Zeilen in welchen das vorgegebene Muster vorkommt
und gibt die Treffer am Bildschirm aus. Die Option -e wirkt wie ein Oder (OR). Man kann
damit also nach mehreren Mustern gleichzeitig suchen. Diese Muster sind sogenannte Reguläre
Ausdrücke (Regular Expressions). Die Muster müssen in manchen Fällen in Anführungszeichen
stehen, damit die Suche erfolgreich ist.
Es gibt unterschiedliche Varianten von grep wie GNU grep, egrep, GNU egrep, fgrep, etc. Zudem
gibt es noch weitere Programme die mit Regulären Ausdrücken arbeiten wie sed und perl.
Diese Beschreibung hier gilt für GNU grep. Abweichungen bei anderen Programmen bzw. Befehlen
sind den jeweiligen Manual-Seiten zu entnehmen.
Optionen:
-
-c
-
(count) gibt nur die Anzahl der Zeilen an in denen das Suchmuster gefunden wurde,
jedoch nicht die Zeilen selbst. Wenn die Option -v verwendet wird, werden die Zeilen
gezählt die das Muster nicht enthalten
-
-e
-
Muss verwendet werden wenn das Muster mit "-" beginnt. Kann aber auch verwendet werden um
mehrere Muster mit "Oder" zu verknüpfen.
-
-H
-
gibt den Dateinamen für jeden Treffer mit aus
-
-i
-
(ignore case) ignoriert die Gross-/Kleinschreibung des Musters
-
-m Anzahl
-
begrenzt die Anzahl der ausgegebenen Treffer auf Anzahl Zeilen
-
-n
-
die Zeilennummern der gefundenen Zeilen, aus den durchsuchten Dateien werden der
Ausgabe vorangestellt
-
-r, -R
-
durchsucht rekursiv alle Dateien in allen Unterverzeichnissen. Dies funktioniert aber
nur mit der Wildcard "*" einwandfrei. Aus diesem Grunde verwendet man
für die rekursive Suche grep zusammen mit dem Befehl find (s. Beispiel unten).
-
-s
-
(supress error messages) unterdrückt Fehlermeldungen
-
-v
-
invertiert die Ausgabe, d.h. es werden die Zeilen in denen das Suchmuster nicht vorkommt
am Bildschirm ausgegeben
Zum Seitenanfang
Mit Regulären Ausdrücken wird eine festgelegte Zeichenfolge beschrieben. Hierzu werden Meta-Zeichen,
(metacharacters) auch Platzhalter genannt und Operatoren verwendet.
Achtung! Auch wenn Reguläre Ausdrücke eine gewisse Ähnlichkeit mit Wildcards aufweisen sind sie
doch recht unterschiedlich und dienen unterschiedlichen Zwecken. Mit Reguläre Ausdrücken sucht man nach
Zeichenfolgen innerhalb von Dateien. Wildcards dienen der Suche nach Dateien.
Prinzipiell steht jedes Zeichen erst einmal für sich selbst. Wenn ich als Muster
"Suchtext"
eingebe. Wird also nach dem Vorkommen der Zeichenfolge "Suchtext" in den angegebenen Dateien gesucht.
Behandlung von Sonderzeichen: Sonderzeichen wie ?, +, {, }, |, (, ), ., ", \ müssen mit
einem Backslash "\" maskiert werden.
Mit der Hilfe von Platzhaltern kann man die Suche spezifizieren. Das Suchmuster muss damit nicht mehr exact der
gesuchten Zeichenkette entsprechen,sondern kann damit abstrakt beschrieben werden.
|
.
|
steht für ein beliebiges Zeichen
|
|
[ ]
|
der Ausdruck in der Klammer ist Platzhalter für genau ein Zeichen aus der Liste
in der Klammer
|
|
[^ ]
|
hiermit werden alle Zeichen aus der Liste ausgeschlossen. Es handelt sich wiederum
um den Platzhalter für genau ein Zeichen
|
|
|
|
Sonderregelungen:
|
|
]
|
wenn man nach diesem Zeichen sucht muss es innerhalb der Klammern
am Anfang stehen
|
|
^
|
dieses darf irgendwo, jedoch nicht am Anfang stehen
|
|
-
|
dieses muss am Ende stehen
|
|
Beispiele:
|
" s"
|
" " gefolgt von "s"
|
|
e.t
|
sucht nach "e" + beliebiges Zeichen + "t"
|
|
[abc]
|
eines der Zeichen "a", "b", "c"
|
|
[^abc]
|
keines der Zeichen "a", "b", "c"
|
|
[^t]
|
kein "t" an dieser Stelle
|
|
ich[^t]
|
findet "ich", aber nicht "nicht"
|
|
[a-f]
|
die Buchstaben "a", "b", "c", "d", "e" und "f"
|
|
[a-z]
|
alle Kleinbuchstaben
|
|
[A-Z]
|
alle Grossbuchstaben
|
|
[a-zäöüßA-ZÄÖÜ]
|
alle Klein- und Grossbuchstaben incl. deutscher Sonderzeichen
|
|
[a-zA-Z-]
|
alle Klein- und Grossbuchstaben und "-"
|
|
[0-9]
|
alle Zahlen
|
|
[a-zA-Z0-9]
|
alle alphanumerische Zeichen (o. deutsche Sonderzeichen)
|
Die bennanten Klassen sind vordefinierte Zeichenkombinationen für die Platzhalter in eckigen Klammern.
|
[:lower:]
|
entspricht
|
a-z
|
|
[:upper:]
|
entspricht
|
A-Z
|
|
[:alpha:]
|
entspricht
|
a-zA-Z und [:lower:] + [:upper:]
|
|
[:digit:]
|
entspricht
|
0-9
|
|
[:alnum:]
|
entspricht
|
0-9a-zA-Z und [:alpha:] + [:digit:]
|
|
[:space:]
|
entspricht
|
einem Leerschritt
|
Die benannten Klassen müssen für die Verwendung nochmals in eckige Klammer
geschrieben werden. Im Muster entspricht
[[:alnum:]] diesem Ausdruck [0-9a-zA-Z]
Mit Hilfe dieser Metazeichen kann man die Begrenzungen von Zeilen und Wörtern beschreiben.
|
^
|
steht für den Zeilenanfang
|
|
$
|
steht für das Zeilenende
|
|
\<
|
steht für Wortanfang
|
|
\>
|
steht für Wortende
|
|
\b
|
steht Wortanfang oder Wortende
|
Beispiele:
|
^D
|
sucht nach grossem D am Zeilenanfang
|
|
^.a
|
sucht nach einem beliebigen Zeichen + "a" am Zeilenanfang
|
|
\.$
|
sucht nach einem "." am Ende der Zeile
|
|
n\.$
|
sucht nach "n" und "." am Ende der Zeile
|
|
\<ich\>
|
sucht nach dem ganzen Wort "ich"
|
|
*
|
das vorangegangene Zeichen darf beliebig oft oder auch gar nicht auftreten
|
|
?
|
das vorangegangene Zeichen darf gar nicht oder einmal auftreten
|
|
+
|
das vorangegangene Zeichen darf beliebig oft, muss aber mindestens einmal auftreten
|
|
{n}
|
das vorangegangene Zeichen tritt n-mal auf
|
|
{n,}
|
das vorangegangene Zeichen tritt n-mal oder öfter auf
|
|
{n,m}
|
das vorangegangene Zeichen tritt mindestens n-mal und maximal m-mal auf
|
Beispiele:
|
dass?
|
findest "das" und "dass"
|
|
[dD]as{1,2}
|
findet "das", "Das", "dass" und "Dass"
|
|
[dD]as\{1,2\}
|
Aber Achtung! Diese beiden Zeichen "{", "}" müssen mit einem
"\" maskiert werden.
|
|
[[:space:]]\{2\}
|
findet 2 Leerzeichen.
|
|
|
|
verbindet zwei oder mehr Ausdrücke mit einem "Oder" (OR)
|
|
()
|
stellt Gruppierungen her. Wiederholungs-Operatoren können auch
auf Gruppierungen angewendet werden.
|
Beispiele:
|
(da|na)ss
|
findet "dass" und "nass"
|
|
\(da\|na\)ss
|
Aber Achtung! Diese Zeichen "(", "|", ")" müssen mit einem "\" maskiert werden.
|
|
Karl\(-Heinz\)\?
|
findet Karl und Karl-Heinz
|
Zum Seitenanfang
Die Beispiele oben dienten dem Verständnis der Regulären Ausdrücke. In der Praxis,
beim Arbeiten mit grep, muss man die Suchmuster ggf. noch in Anführungszeichen einschliessen und
die Maskierung der Sonderzeichen berücksichtigen.
Zudem ist die Erstellung von Regulären Ausdrücken doch meist komplexer als aus den Beispielen
oben ersichtlich ist. Aus diesem Grunde gibt es weiter unten einige Schritt-für-Schritt-Beispiele in denen
ich demonstriere wie man die Suche verfeinern kann um das gewünschte Ergebnis zu ereichen.
Einfache Beispiele:
sucht nach dem Regulären Ausdruck "ich" in der Datei qqk
grep "ich" qqk
oder
grep "ich" < qqk
... und leitet die Ausgabe nach qqk1
grep "ich" < qqk > qqk1
durchsucht alle *.tex-Dateien im aktuellen Verzeichnis nach der Zeichenfolge "emacs"
grep "emacs" *.tex
ermittelt mit der Option -c wie oft die arctan -Funktion in den *.c Dateien verwendet wird
grep -c arctan\(.*\) *.c
Hier wird es etwas komplexer
Dies ist die Datei "adressen", die für einige der nächsten Suchen verwendet wird:
Meier
Müller
Meyer
Schmidt
Hohn
Maier
Mayer
Mayr
Paule
sucht nach Meier, Meyer, Meyer und Mayer in der Datei adressen
klaus@athlon:~/bin/test> grep M[ae][iy]er adressen
Meier
Meyer
Maier
Mayer
und die beiden nächsten Beispiele auch noch nach allen "Meiers" ohne "e" am Ende.
klaus@athlon:~/bin/test> grep "M[ae][iy]e\?r" adressen
Meier
Meyer
Maier
Mayer
Mayr
klaus@athlon:~/bin/test> grep "M[ae][iy]e\{0,1\}r" adressen
Meier
Meyer
Maier
Mayer
Mayr
Dies ist die Datei "gruppe", die für die Beispiele unten verwendet wird:
dass
mass
nass
trocken
maß
maßlos
dieses
hallo
hallohallo, ist da wer?
wort1
wort2
grep -V
Option -e muss verwendet werden, da der Suchbegriff am Anfang ein Minus "-" enthält:
klaus@athlon:~/bin> grep -e "-V" gruppe
grep -V
Ein Beispiel von oben auf der Kommandozeile ausgeführt:
klaus@athlon:~/bin> grep "\(da\|na\)ss" gruppe
dass
nass
Sucht nach wort1 oder wort2:
klaus@athlon:~/bin> grep "wort1\|wort2" gruppe
wort1
wort2
Das lässt sich auch so lösen:
klaus@athlon:~/bin> grep -e "wort1" -e "wort2" gruppe
wort1
wort2
Oder so:
klaus@athlon:~/bin> grep "wort\(1\|2\)" gruppe
wort1
wort2
Eine Gruppierung kann auch mit einem Wiederholungs-Operator vervielfacht
werden:
klaus@athlon:~/bin> grep "\(hallo\)\{2\}" gruppe
hallohallo, ist da wer?
Und als nächstes jetzt ein etwas komplexeres Beispiel für Gruppierungen (in 2 Schritten):
Gesucht werden Benutzer mit der Gruppen-ID 100. Die Gruppen-ID steht
in der Datei passwd im 4. Feld. Jedes der 3 davorstehenden Felder kann
man mit diesem Ausdruck beschreiben "[^:]*:"
Hier jetzt erst einmal die Suche "voll ausgeschrieben":
athlon:/etc # grep [^:]*:[^:]*:[^:]*:100 passwd
games:x:12:100:Games account:/var/games:/bin/bash
klaus:x:1000:100:Klaus Gerhardt:/home/klaus:/bin/bash
test:x:1001:100:test:/home/test:/bin/bash
Und jetzt die ersten 3 Felder in einer Gruppierung
zusammengefasst. Achtung! Der Reguläre Ausdruck muss jetzt
in Anführungszeichen stehen, sonst findet keine Suche statt:
athlon:/etc # grep "\([^:]*:\)\{3\}100" passwd
games:x:12:100:Games account:/var/games:/bin/bash
klaus:x:1000:100:Klaus Gerhardt:/home/klaus:/bin/bash
test:x:1001:100:test:/home/test:/bin/bash
Als nächstes die Suche nach dem doppel "d" in mehreren Schritten:
Dies ist die Datei doppeld:
einfach d
Doppel dd
Dreifach ddd
und noch ein Doppel dd_ende
Mein erster Versuch. Es sollen alle Textstellen gefeunden werden in denen ein
doppeltes "d" vorkommt. 3-fach "d" sollen aber ausgeschlossen sein.
Mein Ausdruck sagt: finde alle Zeilen in denen "dd" vorkommt.
klaus@athlon:~/bin> grep "d\{2\}" doppeld
Doppel dd
Dreifach ddd
und noch ein Doppel dd_ende
Das 3-fach d "d" wird bei meiner Suche jedoch auch gefunden. Denn "dd" ist in "ddd"
ja auch enthalten. Ich versuche es deshalb anders.
Der nächste Ausdruck sagt: Vom Anfang der Zeile an kein d, dies gar nicht oder beliebig oft,
dann dd und zum Ende der Zeile hin kein d, dies gar nicht oder beliebig oft.
klaus@athlon:~/bin> grep "^[^d]*d\{2\}[^d]*$" doppeld
Doppel dd
Jetzt wird allerdings die letzte Zeile aus der Datei doppeld nicht gefunden.
Da diese Zeile ein einzelnes d in dem "und" enthält, wird sie von meinem Ausdruck
"Vom Anfang der Zeile an kein d, dies gar nicht oder beliebig oft" ausgeschlossen.
Ich starte noch einen Versuch. Der unten stehende Ausdruck heisst: Zeilenanfang oder kein d,
dann dd und dann kein d oder Zeilenende.
klaus@athlon:~/bin> grep "\(^\|[^d]\)d\{2\}\([^d]\|$\)" doppeld
Doppel dd
und noch ein Doppel dd_ende
Und diesmal hat es geklappt. Ich erweitere die Datei um zu sehen ob das "dd" auch am
Zeilenanfang bzw. Zeilenende gefunden werden:
einfach d
Doppel dd
Dreifach ddd
und noch ein Doppel dd_ende
dd_ende
anfang_dd
klaus@athlon:~/bin> grep "\(^\|[^d]\)d\{2\}\([^d]\|$\)" doppeld
Doppel dd
und noch ein Doppel dd_ende
dd_ende
anfang_dd
Und es funktioniert. An dem oben stehenden Beispiel sieht man dann auch, dass einige
Erfahrung dazu gehört um komplexere Reguläre Ausdrücke zu bilden.
Im nächsten Beispiel werden, analog zum vorherigen Beispiel, Zeilen mit 2 Leerschritten
gesucht.
Dies ist die Datei spaces. Die Datei enthält am Schluss auch eine Leerzeile:
dies ist ein space
dies sind zwei spaces
dies sind drei spaces
dies sind nochmal zwei spaces
Und dies die Suche mit grep:
klaus@athlon:~/bin> grep "\(^\|[^[:space:]]\)[[:space:]]\{2\}\([^[:space:]]\|$\)" spacetest
dies sind zwei spaces
dies sind nochmal zwei spaces
grep in der Systemadministration:
Filtern eines bestimmten Prozesses:
klaus@athlon:~/bin> ps aux | grep kate
klaus 7929 0.2 4.7 36712 24708 ? S 15:15 0:07 kate [kdeinit] kate
klaus 8129 0.0 0.1 1884 728 pts/2 R+ 16:16 0:00 grep kate
Störend ist allerdings, dass der Prozess mit dem gesucht wird, auch noch im Ergebnis
angezeigt wird. Diesen kann man dann so ausfiltern:
klaus@athlon:~/bin> ps aux | grep kate | grep -v grep
klaus 7929 0.2 4.7 36712 24712 ? S 15:15 0:08 kate [kdeinit] kate
Die Suche nach einem bestimmten Paket, hier das Paket grep:
klaus@athlon:~/bin> rpm -qa | grep grep
grep-2.5.1a-4
Diese Zeile filtert die Angaben zum nmb-Dämon aus der Ausgabe von
/var/log/messages:
athlon:~ # tail -f -n 25 /var/log/messages | grep nmbd
Zum Seitenanfang
Da die rekursive Suche mit grep sehr begrenzt ist, wie oben bei der Option -r erläutert,
kombiniert man für diesen Zweck die Befehle find und grep. find für die Dateisuche, grep
für die Suche nach Regulären Ausdrücken innerhalb der gefundenen Dateien. find übergibt
mit der Aktion -exec die gefundenen Dateien an grep zur Weiterverarbeitung:
find /etc -name "*" -exec grep -nsH "BOOT_" {} \;
-
find sucht ab dem Verzeichnis /etc nach allen Dateien ("*")
und gibt die Dateiliste an grep weiter
-
grep sucht in allen Dateien nach "BOOT_"
-
-H gibt die Dateinamen incl. Pfad mit aus
-n gibt die Zeilenummer der Textstelle an
-s unterdrückt Fehlermeldungen
Siehe auch: man 1 grep, info grep
Zum Seitenanfang
Ansonsten wird der Befehl genauso angewandt wie grep, deshalb erfolgt hier keine
weitere Beschreibung.
Siehe auch: man 1 zgrep, info zgrep, man 1 grep, info grep
Zum Seitenanfang
© Klaus Gerhardt • http://linuxseiten.kg-it.de
-
Dieses Dokument darf in unveränderter Form vervielfältigt und weitergereicht werden,
sofern diese Nutzung privat erfolgt.
-
Der Name des Autors muss genannt werden, sowie die in diesem Absatz festgelegten Nutzungsbedingungen.
-
Eine kommerzielle Nutzung ist nur mit der Zustimmung des Autors erlaubt.
-
Die Vervielfältigung entsprechend den o.g. Bedingungen ist sowohl in elektronischer Form,
als auch auf Papier zulässig.
Der Autor haftet weder für die Anwendung, der in diesem Dokument
beschriebenen Verfahren, noch für die Anwendung von beigefügten Shell-Skripten.
Die Haftung liegt alleine beim Anwender.
Shellskripte, die mit einem Link von diesem Dokument aus heruntergeladen werden
können, bilden einen Teil dieses Dokumentes und müssen unverändert zusammen mit diesem Dokument
weitergereicht werden. Man kann diese Shellskripte jedoch auch separat verwenden. Dann darf man
sie nach belieben verändern.
|