![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
||||||||
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
|||||||
![]() |
|||||||
![]() |
|
||||||
![]() |
Grep-Ergebnisse farbig anzeigen, Online-Hilfe in SkriptenBuntes mit HilfestellungMichael Schili |
Wie schön wär's, wenn der Unix-grep
endlich Perls reguläre Ausdrücke verstünde! Was gäb' ich, wenn in den
passenden Zeilen auch noch die Treffer farbig markiert wären! Ja hätt' ich
dieses Tool nur in meinem Werkzeugkasten! Heute macht der Perl-Onkel Träume
wahr.
Das heute vorgestellte Skript cgrep
bietet in der Tat die gewünschte Funktionalität. Es erwartet auf der
Kommandozeile einen regulären Ausdruck und durchstöbert die angegebenen
Dateien oder die Standardeingabe nach dem Suchmuster. Gefundene Zeilen gibt
es aus und unterlegt die Treffer farbig.
Abbildung 1 zeigt, wie cgrep
sein eigenes Listing nach dem Wort
rex
durchsucht. Das Kommando cgrep rex cgrep
bringt sieben Zeilen zum Vorschein, die insgesamt neunmal das Wort rex
lila unterlegen.
Da cgrep
nicht nur grep
s reguläre Ausdrücke versteht, sondern den vollen Perl-5-Satz, kann man,
wie in Abbildung 2 demonstriert, auch nach alleinstehenden Ziffern suchen.
Der reguläre Ausdruck hierzu lautet
\b\d+\b
: Eine Wortgrenze, gefolgt von einer oder mehreren Ziffern, gefolgt von
einer abschließenden Wortgrenze. Dieses Muster findet zwar die Fünf in Perl 5
, aber zum Beispiel nicht Perl5
, da im zweiten Fall keine Wortgrenze zwischen
Perl
und 5
liegt.
Term::ANSIColor
bietet die Funktion colored
an, die einen ihr übergebenen Text mit Kontrollsequenzen versieht, die ihn
farbig unterlegen, falls er auf einem Terminal ausgegeben wird.
colored
erwartet zwei Parameter: Einen Skalar, der den einzufärbenden Text enthält
und einen weiteren Skalar, der die Malerarbeiten als Vorder- und
Hintergrundfarbe beschreibt. 'white on_blue'
selektiert beispielsweise weißen Text auf blauem Hintergrund:
use Term::ANSIColor; print "Der ", colored("Himmel", "white on_blue"), " über Bayern.\n";
Dabei exportiert das Modul Term::ANSIColor
die Funktion colored
automatisch in das Hauptprogramm, so dass dieses colored
ohne Modulzusatz aufrufen kann. Mehr zu diesem Thema und weiteren
nützlichen Funktionen von Term::ANSIColor
findet sich in [1].
cgrep
zeigt, wie's geht: Es zieht zunächst die Zusatzmodule
Term::ANSIColor
zum Einfärben, Getopt::Std
zur Kommandozeilenanalyse und das weiter unten detailliert besprochene Pod::Usage
zum eleganten Ausdrucken der Bedienungsanleitung herein. Wer noch nicht
perl 5.6.0
fährt, muss die Module von Hand nachinstallieren, Abschnitt Installation zeigt wie.
Die Funktion getops
in Zeile 12 holt eventuell gesetzte Schalter
-h
, -p
und -i
von der Kommandozeile und setzt demensprechend die Hasheinträge $opt{h}
, $opt{p}
oder $opt{i}
.
Zeile 16 holt den regulären Ausdruck als String von der Kommandozeile,
Zeile 19 druckt eine Fehlermeldung mit Hilfestellung aus und bricht das
Programm ab, falls vergessen wurde, einen Ausdruck anzugeben. Falls der
Benutzer cgrep
den Schalter -i
zum Ignorieren von Groß- und Kleinschreibung mitgab, stellt Zeile 22 den
regulären Ausdruck den String (?i)
voraus, was Perl -- wie der Modifizierer /.../i
-- dazu veranlasst, beim Pattern-Matching keinen Wert auf Groß- oder
Kleinschreibung zu legen.
Zeile 25 compiliert den Ausdruck, der ja als String vorliegt, mit dem qr
-Operator in einen Regex-Ausdruck. Dies verursacht einen tödlichen Fehler,
falls der Ausdruck syntaktisch nicht den Perl-5-Bedingungen entspricht. Das eval
-Konstrukt fängt dies ab, gibt im Fehlerfall einen falschen Wert zurück und
mit pod2usage
eine Fehlermeldung einschließlich Hilfestellung aus.
Geht alles soweit gut, iteriert Zeile 29 über alle Zeilen der auf der Kommandozeile namentlich bereitgestellten Dateien, oder, falls sich keine Namen finden, über alle Zeilen aus dem Standard-Input.
Zeile 32 prüft, ob die aktuell analysierte Zeile dem regulären Ausdruck
genügt. Falls sich ein Treffer findet, ruft das Suche-Ersetze-Konstrukt in
den Zeilen 35-37 dafür die Färbefunktion colored
aus dem Term::ANSIColor
-Modul auf. Der Modifizierer /g
stellt sicher, dass dies für alle Treffer in einer Zeile geschieht, und
auch falls der reguläre Ausdruck aus einer Reihe von Alternativen (wie in /a|b|c/
) besteht, sorgt die Treffervariable $&
dafür, dass jeweils der richtige Text eingefärbt wird. Der Modifizierer /x
erlaubt es, den Regex-Salat der Übersicht halber auf mehrere Zeilen zu
verteilen, und /e
sorgt dafür, dass perl
den Ersetzungsausdruck als Code interpretiert, also tatsächlich die
Funktion colored()
aufruft und nicht eine sture Text-für-Text-Ersetzung durchführt.
Traf der Ausdruck die aktuelle Datenzeile nicht, druckt sie
cgrep
in Zeile 42 dennoch aus, falls der Benutzer den Schalter
-p
auf der Kommandozeile setzte.
Noch ein Beispiel: Zwei gleiche Worte, die direkt hintereinanderstehen, deuten meistens auf einen Tippfehler hin -- schau'n wir mal:
cgrep '\b(\w+)\s+\1\b' cgrep
sucht nach einer Wortgrenze, einem Wort, Leerzeichen und das gleiche Wort
nochmal in Folge, abgerundet von einer Wortgrenze. Und, in der Tat in Zeile
28 von Listing cgrep
hat sich ein Fehler eingeschlichen, wie Abbildung 3 zeigt.
cgrep
funktioniert -- auch die Leute, die zu faul zum Manualseitenlesen sind --,
nutzt cgrep
das Modul Pod::Usage
, das mit der Funktion pod2usage
die Möglichkeit bietet, die in ein Skript mit POD (Plain Old Documentation)
eingebettete Dokumentation teilweise oder ganz im Textformat auszugeben.
perl
-Interpreter ignoriert diese Information geflissentlich und Werkzeuge wie perldoc
oder die Filter pod2man
, pod2html
etc. extrahieren sie auf Wunsch und wandeln sie in das gewünschte
Zielformat um. Der Aufruf perldoc Skriptname
generiert üblicherweise eine Manualseite aus dem Skript und zeigt sie an.
Das Modul
Pod::Usage
hingegen erlaubt es, auf die eingebettete Dokumentation schon aus dem
Skript heraus zuzugreifen -- üblicherweise falls seitens des Benutzers ein
Eingabefehler vorliegt und das Skript die fällige Fehlermeldung mit einer
mehr oder weniger detailierten Bedienungsanleitung versehen will.
pod2usage
gibt üblicherweise eine ihr als String übergebene Fehlermeldung aus, und
druckt außerdem die Sektionen SYNOPSIS
,
OPTIONS
und ARGUMENTS
einer eingebetteten Manualseite. Danach bricht pod2usage
es das Skript ab. Der optionale Parameter -verbose
steuert die Leutseligkeit des Programms -- für den Wert 0
gibt es nur die SYNOPSIS
-Abteilung aus, für den Wert 1
die oben erwähnten drei Sektionen und für Werte größer gleich 2
die gesamte Manualseite. Die POD-Anweisungen nutzt perl
dazu, einen ansprechend formatierten Text zu generieren. Typische
Anwendungen von pod2usage
sind:
# SYNOPSIS und OPTIONS/ARGUMENTS pod2usage( $message ); # Nur SYNOPSIS pod2usage( -message => $message, -verbose => 0 ); # SYNOPSIS und OPTIONS/ARGUMENTS pod2usage( -message => $message, -verbose => 1 ); # Gesamte Manualseite pod2usage( -message => $message, -verbose => 2 );
Ruft so jemand das Skript cgrep
ohne regulären Ausdruck auf, springt Zeile 19 ein und ruft pod2usage
auf, welches die Ausgabe nach Abbildung 4 liefert, die dem Benutzer die
richtige Anwendung des Programms nahelegt.
cgrep -h
aufruft, verzweigt Zeile 14 zu pod2usage
und stellt mit verbose
-Level 2 den Dokumentationsmodus ein. Abbildung 5 zeigt die Textdarstellung
im X-Terminal.
cgrep
im Unix-üblichen Manualseitenformat anzuzeigen:
pod2man cgrep | nroff -man | less
extrahiert die Information aus dem Skript und übergibt sie dem Unix-üblich
Manualformatierer nroff
, der diese wiederum durch den Pager less
pfeift. Und auch vor HTML scheut sich POD nicht:
pod2html cgrep >cgrep.html
erzeugt HTML-Text aus dem POD-Markup und legt ihn in cgrep.html
ab. Abbildung 6 zeigt, wie der Browser die Manualseite cgrep.html
darstellt.
Listing cgrep | ||
001 #!/usr/bin/perl -w 002 ################################################## 003 # cgrep - Highlight regular expression matches 004 # 005 # Mike Schilli, 2000 006 ################################################## 007 008 use Term::ANSIColor; 009 use Pod::Usage; 010 use Getopt::Std; 011 012 getopts( 'hpi', \%opt ); 013 014 pod2usage(-verbose => 2) if $opt{h}; 015 016 my $rex = shift; 017 018 ### Called without regex? 019 pod2usage("Missing argument") unless defined $rex; 020 021 ### Regex modifiers if requested 022 $rex = "(?i)$rex" if $opt{i}; 023 024 ### Compile regex and complain if it's broken 025 eval { $rex = qr($rex) } or 026 pod2usage "Invalid Regex: $rex"; 027 028 ### Loop over all all lines of input 029 while(<>) { 030 031 ### Match? 032 if( /$rex/ ) { 033 034 ### Colorize with Term::ANSIColor 035 s/$rex 036 /colored($&, 'yellow on_magenta') 037 /egx; 038 039 print; 040 } else { 041 ### Print anyway if -p 042 print if $opt{p}; 043 } 044 } 045 046 __END__ 047 048 =head1 NAME 049 050 cgrep - Highlight regular expression matches 051 052 =head1 SYNOPSIS 053 054 cgrep [options] regex [file ...] 055 056 Options: 057 -h get help 058 -p print all lines 059 -i ignore case 060 061 =head1 OPTIONS 062 063 =over 8 064 065 =item B<-h> 066 067 Prints this manual page in text format. 068 069 =item B<-p> 070 071 Prints all lines, no matter if they match or not. 072 073 =item B<-i> 074 075 Activate "ignore case" mode in the regular expression match, just like 076 the perl regex modifier /.../i. 077 078 =back 079 080 =head1 DESCRIPTION 081 082 B<cgrep> reads the files provided on the command 083 line - or standard input in case there are none, 084 just like C<grep> does. 085 086 It takes a mandatory C<regex> parameter, which 087 must be a valid Perl 5 regular expression. It 088 will print out all lines matching the regex and 089 colorize the matches accordingly. 090 091 Be sure to escape regex metacharacters if they're 092 meant literally (C<|> =E<gt> C<\|>). Quote the 093 regex on the command line if it contains shell 094 metacharacters. 095 096 =head1 EXAMPLES 097 098 Print all lines in C<myfile.dat> and 099 C<yourfile.dat> containing the word I<main> 100 and colorize all occurrences of the word C<main>: 101 102 cgrep main myfile.dat yourfile.dat 103 104 Print and colorize all numbers in file C<file>: 105 106 cat file | cgrep '\b\d+\b' 107 108 Print all lines of the file C<file> and colorize 109 occurrences of the word C<word>: 110 111 cgrep word file 112 113 =head1 AUTHOR 114 115 2000, Mike Schilli <mschilli1@aol.com> |
Installation |
Die Zusatzmodule
perl -MCPAN -eshell cpan> install Term::ANSIColor cpan> install Pod::Usage installiert die Module auf der lokalen Maschine. Fröhliches greppen! |
Infos |
|
Der Autor |
Michael Schilli arbeitet als Web-Engineer für AOL/Netscape in Mountain View, Kalifornien. Er ist Autor des 1998 bei Addison-Wesley erschienenen (und 1999 für den englischsprachigen Markt als "Perl Power" herausgekommenen) Buches "GoTo Perl 5" und unter michael@perlmeister.com zu erreichen. Seine Homepage: http://perlmeister.com |
Copyright © 2000 Linux New Media AG