Seiten-Inhalt

One-liner / Einzeiler / Snippets / Schnipsel - für/mit Perl

Hier ein paar nützliche Schnipsel, bei denen Perl bei der täglichen Arbeit unterstützen kann:

SNIP 01: Zeit auf Rechner mit Zeit-Server abgleichen

Verschiedene Rechner bieten über das Internet einen Dienst an, der es erlaubt, die (atom-)genaue, aktuelle Zeit abzugreifen. Dies kann man nutzen, um mit Perl darauf zuzugreifen und per Batch-Datei oder regelmäßig ausgeführtem cron-Job die Zeit auf dem lokalen System immer genauestens einzustellen:

$ perl -e "use Net::Time qw(inet_time); use Time::localtime; 
  $tm=localtime(inet_time('ptbtime1.ptb.de','tcp')); 
  print sprintf(\"%02d:%02d:%02d\", $tm->hour,$tm->min,$tm->sec);" | time

(Download als Text)
Erklärung: Mit "perl -e" kann man den Interpreter direkt anweisen, Programm-Code sofort auszuführen; dieser wird in Anführungszeichen eingeschlossen an diesen übergeben. Zuerst werden die notwendigen Module eingebunden. Die Zeit wird bei einem der Timeserver (hier bei ntps1-0.cs.tu-berlin.de) in "Epochensekunden" abgefragt und in $tm zwischengespeichert. Mittels sprintf wird die Ausgabe formatiert und mit print ausgegeben. Durch die Pipe "|" wird die Ausgabe an das folgende Programm weitergeleitet.
(Achtung: Zur Übergabe an die Kommandozeile bitte die Zeilenumbrüche und überflüssige Leerzeichen entfernen. Es handelt sich bei obigen Zeichen um *eine* Zeile!)

SNIP: Suchen und ersetzen in Text-Datei

Immer wieder kommt es vor, daß man eine oder gar mehrere Dateien hat, in der ein bestimmter Text durch einen anderen ersetzt werden soll. Dies kann man mit folgendem Schnipsel realisieren:

$ perl -pi -e "s/OldText/NewText/g" file.txt

Häufig passiert es beim Zusammenspiel von Windows und Linux, daß Dateien mit dem Zeilenumbruch in Textdateien Probleme haben. Windows speichert für einen Zeilenumbruch ein "\n\r" und Linux nur ein "\n" - die Darstellung unter Linux wird dann zu jedem Zeilenende mit einem "^M" gestört. Um dies zu verhindern kann man nun also einfach

$ perl - pi -e "s/\r//g;" *.pl

tippen.

SNIP: Mehrere Dateien gleichzeitig nach best. Muster umbenennen

Unter Windows eine Mange von Dateien in einem Rutsch umzubenenen ist eigentlich unmöglich. Unter Linux-Systemen gibt/gab es das Programm mmv ('mutiple move') - hiermit kann man Dateien nach frei definierbaren Mustern umbenennen.
Um nun auch unter Windoofs Abhilfe zu schaffen, kann man perl benutzen:

$ perl -e "for my $n (<*.jpg>){my $a=$n; $a=~s!^(.).*?(...a?\.jpg$)!$1-$2!; rename $n,$a}"

Hierbei wird ein regulärer Ausdruck genutzt, um aus dem bestehenden Dateinamen einen neuen zu "generieren"...

SNIP: Differenz zweier Texte bzw. Arrays

In der Linux-Welt gibt es ein schönes Tool 'diff' - mit diesem kann man unterschiedliche Zeilen in einer Datei finden. Diesen wird ein '<' oder '>' vorangestellt, um kenntlich zu machen, ob die Zeile "zu viel" - oder "zu wenig" ist.

So habe ich überlegt, ob man sowas nicht auch mal fix in ein paar Zeilen in perl lösen kann. Es geht erstaunlich einfach:

#!/usr/bin/perl -w
use strict;
use Data::Dumper;

my (%ha, %hb);

my @a = (1,2,3,4,5,6); 
my @b =       (4,5,6,7,8,9); 

@ha{@a} = (1) x @a;
@hb{@b} = (1) x @b;

my @diff = ( (map { ['<', $_] } grep { !($hb{$_}) } @a),
             (map { ['>', $_] } grep { !($ha{$_}) } @b) );

print Dumper (\@diff);

Um den Schnipsel verständlich zu machen, betrachte man nur die folgende Textzeile

map { ['<', $_] } grep { !($hb{$_}) } @a

Zum Verständnis liest man die Zeile am besten von hinten nach vorne: Eines der zu vergleichenden Arrays (@a) wird an ein grep übergeben. Dieses grep läßt nur Einträge durch, die in dem in den Zeilen darüber generierten Hash nicht vorhanden sind. Nun wird diese Ausgabe noch durch ein map mit den Rein-/Raus-Zeichen versehen. Fertig. (Durch die Klammerung oben im Source und das Komma werden die beiden Ergebnisse der map-grep-Kombination als Array miteinander verknüpft - so wird das Ergebnis-Differenz-Array in "einem Schwung" erzeugt.

(Die Zeile @ha{@a} = (1) x @a; füllt ein Hash mit den Array-Elementen als keys und weist ihnen jeweils den Wert 1 zu.)

(Um zwei Texte zeilenweise zu vergleichen kann man diese in @a und @b einlesen. Bspw. durch my @a = split /\n/, $text;)

SNIP: Fortschrittszähler in Perl

Nun will man vielleicht für einen etwas länger andauernden Prozeß eine Fortschrittsanzeige implementieren. Eine lange Liste an Zahlen o.ä. ist da wahrscheinlich nicht wirklich das, was man sucht?! So kann man in Perl aber auch mit "\b" einen Rückschritt auf der Kommandozeile ausgeben. Das folgende Beispiel zeigt einen Zähler, der einen Countdown von 10 bis 1 hinunterzählt:

#!perl/bin/perl -w
use strict;

$| = 1;   # Ausgabepuffer für jeden Schreibvorgang leeren

for my $i ( reverse 1..10 ) {
    printf ("\b\b\b\b%4d", $i);
    sleep 1;
} # for

Auf diese Weise bekommt man vielleicht auch fix einen "schicken" Tea-Timer (90 Sekunden für grünen Tee):

perl -e "$|=1; for (reverse 1..90) {printf(\"\b\b%2d\", $_); sleep 1} print \"\a\";"

Drucken
letzte Änderung: 18.Sep 2005

rechte Spalte

Felicitas-Fernsehservice

Ein E-Mail-Dienst, der Ihnen täglich eine Auswahl des TV-Programms zusendet, das anhand einer individuellen Suchwortliste erstellt wurde.
Klicken Sie hier.