Aus Linux-Magazin 09/2011

Perl-Skripte reproduzierbar umziehen

© zettberlin, photocase.com

Wer viel in der Shell arbeitet und navigiert, nach Textstücken sucht oder CPAN-Module installiert, wird die hier vorgestellten Helferskripte bestimmt schnell schätzen lernen.

Neulich zog ich auf einen neuen Entwicklungs-Desktop um und packte die Gelegenheit beim Schopf, mein überquellendes Homeverzeichnis nicht nur aufzuräumen, sondern neu aufzubauen. Dort hatten sich über die Jahre Hunderte von teilweise schon wieder obsoleten Helferskripten angesammelt. Um Ordnung in das Chaos zu bringen, beschloss ich, wirklich bei null anzufangen und die erst bei der täglichen Tipparbeit tatsächlich vermissten Skripte nachzuinstallieren – in reproduzierbarer Art und Weise, versteht sich, auf dass der nächste Umzug wie von allein vonstattengehe.

Versioniert mit Link

Alle Skripte sollen danach in Unterverzeichnissen verschiedener Git-Repositories liegen. Damit der Benutzer die Helferlein ohne Pfadangabe aufrufen kann, zeigen Symlinks vom »bin« -Pfad des Homeverzeichnisses zu den eigentlichen Skripten. Ein weiteres Skript, »binlinks« , ordnet in seinem »DATA« -Bereich den ins Git-Repository eingecheckten Skripten Links im lokalen »bin« -Verzeichnis des Users zu. So verbleibt zum Beispiel das Skript »logtemp« zum Auslesen des in [2] vorgestellten Temperaturfühlers im Git-Repository »articles« , während das handgeschriebene Konvertierwerkzeug »cvs2git« im Schilli-Labs-Repository »sandbox« aufgehoben ist.

Kommt ein neues Skript in den »bin« -Bereich hinzu, trägt der Entwickler es ans Ende des »DATA« -Bereichs von »binlinks« ein und ruft Letzteres auf (Listing 1). Es klappert dann alle Einträge ab, verifiziert, ob der gewünschte Link in »~/bin« schon existiert, und legt ihn nötigenfalls an. Dass »binlinks« selbst wiederum in einem Git-Repository liegt, sollte klar sein. Es nutzt das Modul Sysadm::Install vom CPAN – einzig wegen dessen Funktion »mkd()« , die neue Verzeichnisse ohne Murren anlegt und mit Log4perl-Ausgaben zum Ablauf Auskunft gibt.

Listing 1

binlinks

01 #!/usr/local/bin/perl -w
02 use strict;
03 use Log::Log4perl qw(:easy);
04 use File::Basename;
05 use Sysadm::Install qw(mkd);
06
07 Log::Log4perl->easy_init($DEBUG);
08
09 my ($home) = glob "~";
10 my $home_bin = "$home/bin";
11
12 while (<DATA>) {
13 chomp;
14
15 my ($linkbase, $src) = split ' ', $_;
16
17 $src = "$home/$src";
18 my $binpath = "$home_bin/$linkbase";
19
20 if (-l $binpath) {
21 DEBUG "$binpath already exists";
22 next;
23 } elsif (-e $binpath) {
24 ERROR "$binpath already exists, ",
25 "but not a link!";
26 next;
27 }
28
29 INFO "Linking $binpath -> $src";
30
31 symlink $src, $binpath
32 or LOGDIE
33 "Cannot link $binpath->$src ($!)";
34 }
35
36 __DATA__
37 logtemp git/articles/temper/eg/logtemp
38 cvs2git git/sandbox/cvs2git/cvs2git

Folge dem Link

So handelt es sich bei einem aufgerufenen Skript häufig um einen Symlink. Wenn ein Symlink zu einer Datei in einem anderen Verzeichnis zeigt, möchten Entwickler gerne mit »cd« dorthin wechseln. Dies erledigt das Kommando »lcd« mit dem Link als Parameter (Abbildung 1).

Abbildung 1: Die hier genutzte Funktion »lcd« wechselt in das Verzeichnis mit dem Skript, auf das ein Symlink zeigt.

Abbildung 1: Die hier genutzte Funktion »lcd« wechselt in das Verzeichnis mit dem Skript, auf das ein Symlink zeigt.

Alte Unix-Hasen wissen natürlich, dass ein Skript nicht das aktuelle Verzeichnis des Aufrufers wechseln kann. Skripte laufen in einer Subshell ab, und bei deren Beendigung sind für den Aufrufer keine nachhaltigen Nebenwirkungen bemerkbar. Aus diesem Grund ist »lcd« im Startskript ».bashrc« der Shell als Bash-Funktion definiert:

function lcd () { cd `symlinkdir $1`; \ pwd; ls; }

Ruft der Anwender nun »lcd bin/cvs2git« auf, dann übergibt die Bash-Funktion das Argument »bin/cvs2git« an das Skript »symlinkdir« und ruft das Shellkommando »cd« mit dessen Ausgabe auf. Die Implementierung von »symlinkdir« ist in Listing 2 zu sehen.

Listing 2

symlinkdir

01 #!/usr/local/bin/perl -w
02 use strict;
03 use File::Basename;
04
05 my($link) = @ARGV;
06
07 die "No link specified" unless $link;
08 die "$link not a symbolic link"
09 unless -l $link;
10
11 while(-l $link) {
12 $link = readlink($link);
13 }
14
15 $link = dirname($link) unless -d $link;
16 print "$link\n";

Das Skript folgt mit der Systemfunktion »readlink()« dem als Parameter überreichten Link und wiederholt dies so lange, bis das Ergebnis kein Link mehr ist. Die Funktion »dirname()« aus dem Modul File::Basename extrahiert aus dem resultierenden Pfad das Verzeichnis und Zeile 16 gibt es auf der Standardausgabe aus, wo die Bash-Funktion »lcd()« es aufschnappt, dorthin wechselt, es mit »pwd« ausgibt und mit »ls« die dort liegenden Einträge auflistet.

Sparsamer CPAN-Installierer

Kaum ein Perl-Snapshot kommt ohne zusätzlich zu installierende CPAN-Module aus. Üblicherweise klappt dies ja auch kurz und schmerzlos mit einer CPAN-Shell, die entweder mit »perl -MCPAN -eshell« aufrufbar ist oder mit dem neueren Perl-Distributionen beiliegenden Skript »cpan« .

Allerdings führt der Ressourcenhunger der CPAN-Shell auf Billighost-Accounts schnell zum Rauswurf. Abbildung 2 zeigt, was schon nach einigen Sekunden auf meinem Shared-Hosting-Provider Dreamhost passiert, ohne dass die CPAN-Shell auch nur das gewünschte Modul vom CPAN geladen hätte. Angeblich verbraucht es zu viel RAM-Speicher, und damit die anderen Shared Accounts nicht leiden, zieht Dreamhost – wohl etwas übereilt – die Notbremse.

Abbildung 2: Zu viel für einen Billighoster: Eine CPAN-Shell zum Installieren eines Perl-Moduls führt zum Ziehen der Notbremse.

Abbildung 2: Zu viel für einen Billighoster: Eine CPAN-Shell zum Installieren eines Perl-Moduls führt zum Ziehen der Notbremse.

Rettung naht in Gestalt des CPAN-Moduls App::cpanminus. Abbildung 3 zeigt die kurze Ausgabe des unscheinbaren Tausendsassas, der so wenig Ressourcen verbraucht, dass es selbst meinem Hoster mit seinen strengen Richtlinien nicht auffällt. Wie sein großer Bruder »CPAN.pm« weiß auch »cpanminus« mit lokalen Modulpfaden umzugehen.

Abbildung 3: Das Ressourcen-schonende CPAN-Modul App::cpanminus installiert mit »cpanm« problemlos das gewünschte Modul.

Abbildung 3: Das Ressourcen-schonende CPAN-Modul App::cpanminus installiert mit »cpanm« problemlos das gewünschte Modul.

Damit der User CPAN-Module mit einem nicht privilegierten Account installieren kann und auch nicht die heilige Ordnung des Paketmanagers durcheinanderbringt, raten Experten dringend dazu, »local::lib« zu verwenden, falls die eingesetzte Linux-Distribution benötigte Perl-Module nicht im Repository führt.

Das Modul »local::lib« installiert der Admin, ein letztes Mal als Root, am geschicktesten mit Hilfe des Paketmanagers, unter Ubuntu zum Beispiel folgendermaßen:

sudo apt-get install liblocal-lib-perl

Erlaubt ein Hoster keinen Rootzugriff und lässt sich auch nicht erbarmen, das nützliche »local::lib« per Admin-Eingriff nachzuinstallieren, lädt der Benutzer den Tarball selbst vom CPAN, entpackt ihn und ruft

perl Makefile.PL --bootstrap
make install

auf. Künftig mit einer CPAN-Shell installierte Module landen dann im Verzeichnis »perl5« unter dem Heimverzeichnis des unprivilegierten Users. Wenn dieser anschließend noch das Kommando

eval $(perl -I$HOME/perl5/lib/perl5-Mlocal::lib)

in die Startup-Datei seiner Shell einhängt, normalerweise ».bashrc« , setzt es die Variablen »PERL_MM_OPT« und »PERL5LIB« . Das bewirkt einerseits, dass sowohl die CPAN-Shell als auch »cpanminus« bei »make install« neu installierte Module lokal im Homeverzeichnis installieren. Andererseits finden aufgerufene Skripte, die neu installierte Module mit »use XXX« einbinden, diese dann auch. Falls die Skripte (etwa als Cronjob) nicht über die Environment-Variablen aus ».bashrc« verfügen, tut es auch ein explizit eingetragenes »use local::lib« im Programmcode vor dem Laden der benötigten lokal installierten Module.

Suchen nach Text

Oft weiß der Benutzer, dass sich unterhalb des aktuellen Pfades irgendwo eine Datei versteckt, in der sich ein gesuchter Textstring »Blabla« befindet. In der Shell ließe sich nun ein Find-Befehl wie etwa

find . -type f -exec grep  Blabla  {}/dev/null \;

absetzen, aber das ist extrem viel Tipparbeit und erfordert einiges Nachdenken, speziell wegen des Tricks mit »/dev/null« , das bei Einzeltreffern auch den Dateinamen anzeigt, und mit dem seltsamerweise erforderlichen maskierten Semikolon, das der Option »-exec« zeigt, dass das ihr übergebene Kommando damit endet.

Früher hatte ich ein Skript »findgrep« , das mit Perls File::Find-Modul eine rekursive Textsuche startete, aber seit es »ack« [3] gibt, lade ich stattdessen das mächtige Kommando einfach vom CPAN und tippe

ack  Blabla 

ein – fertig ist der Lack. Allerdings ist das Skript sehr penibel mit Dateitypen: Nur was es aufgrund der Namensendung als textähnliche Datei ansieht, untersucht es auch. Wer alle Dateien durchforsten will, muss »ack -a Blabla« eingeben.

Wer gesteigerten Wert auf Performance legt, ist in einem Git-Repository mit der oft übersehenen Funktion

git grep  Blabla 

weit besser bedient. Da Git die von ihm verwalteten Dateien in einem Index abspeichert, braucht es für die rekursive Suche keine Dateibäume zu durchforsten und schlägt deshalb den ungeschlachten Ansatz gerade bei Dateien, die noch nicht im Buffercache des Operationssystems liegen und in tief verschachtelten Ordnern ausharren, um Längen.

Automatisch formatiert

Damit selbst geschriebene Perl-Skripte vorgegebenen Normen genügen, schickt der ordnungsliebende Programmierer sie am Ende durch den Beautifyer »perltidy« . Dieses Skript ist als CPAN-Modul erhältlich und versteht eine Fülle von Konfigurationen, die jedem Stil gerecht werden. Wo stehen die geschweiften Klammern – in der If-Zeile oder in der nächsten? Kommt das »else« direkt nach der schließenden geschweiften Klammer oder erst nach einem Zeilenumbruch? Leerzeichen zwischen runden Klammern bei Funktionsaufrufen und deren Argumenten? Und – ganz wichtig – wie groß ist die maximale Zeilenlänge, ab wann soll der Formatierer lange Codezeilen umbrechen?

Die Manualseite von »perltidy« listet alle Optionen auf und beschreibt deren Wirkung. Listing 3 zeigt die Konfiguration für Perl-Listings im Linux-Magazin. Die Zeilenbreite beträgt 43 Zeichen, Zeilen in Blöcken rückt der Formatierer um zwei Zeichen ein »-i=2« . Bricht er eine Zeile um, rückt er den Zeilenrest auf der nächsten ebenfalls um zwei Zeichen ein »-ci=2« . Else-Anweisungen folgen direkt ohne Zeilenumbruch nach der schließenden geschweiften Klammer des If-Blocks (Cuddled Else, »-ce« ).

Listing 3

perltidyrc

01 # perltidy-Optionen für Perlskripts im Linux-Magazin
02
03 -l=43 # line width
04 -i=2 # 2 cols indent
05 -ci=2 # 2 cols continuation indent
06 -ce # cuddled else
07 -vt=2 # vertical tightness
08 -nbbc # no blank lines before whole-line comments

Und da Platz im Linux-Magazin stets Mangelware ist und die Redakteure gern damit geizen, steht die Vertical Tightness, also die vertikale Textdichte, auf dem höchsten Wert »-vt=2« . Bei dieser Option geizt wiederum der Formatierer mit Zeilenumbrüchen wie’s nur geht. Auch um Platz zu sparen, bestimmt »-nbbc« noch, dass vor ganzzeiligen Kommentaren keine Leerzeilen stehen.

Damit der Formatierer ein Perl-Skript mit den definierten Optionen ummodelt, ruft der Entwickler ihn mit

perltidy -pro=  Pfad /perltidyrc  Skriptname 

auf, worauf er, falls das Skript syntaktisch korrekt ist, die Datei »scriptname.tdy« erzeugt, die entsprechend umformatiert ist. Wer möchte, der definiert mit

:nnoremap <buffer> <silent> X :w<Enter>1GdG\
:.!perltidy -pro=  Pfad /perltidyrc <%<Enter>

ein Vim-Kommando, das die Formatierung im Editor vornimmt, falls der Benutzer [Shift]+[x] drückt. Bequemer geht es nun wirklich nicht mehr. (uba)

Infos

  1. Listings zu diesem Artikel: ftp://www.linux-magazin.de/pub/listings/magazin/2011/09/Perl
  2. Michael Schilli, “Klimaforschung”: Linux Magazin 10/10, https://www.linux-magazin.de/Heft-Abo/Ausgaben/2010/10/Klimaforschung
  3. »ack« : http://betterthangrep.com

Der Autor

Michael Schilli arbeitet als Software-Engineer bei Yahoo in Sunnyvale, Kalifornien. Er hat “Goto Perl 5” (auf Deutsch) und “Perl Power” (auf Englisch) für Addison-Wesley geschrieben und ist unter mailto:mschilli@perlmeister.com zu erreichen. Seine Homepage ist http://perlmeister.com.

DIESEN ARTIKEL ALS PDF KAUFEN
EXPRESS-KAUF ALS PDFUmfang: 3 HeftseitenPreis €0,99
(inkl. 19% MwSt.)
LINUX-MAGAZIN KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Readly Logo
E-Mail Benachrichtigung
Benachrichtige mich zu:
0 Kommentare
Älteste
Neuste Beste Bewertung
Inline Feedbacks
Alle Kommentare anzeigen
Nach oben