Archiv des Autors: romeofox

Dateien eines Jahres archivieren

Heute stand ich (mal wieder) vor der Aufgabe, in einem Verzeichnis alle Dateien vom Vorjahr zu archivieren.

Im Artikel „Dateien an Hand des Datums und der Uhrzeit finden“ habe ich gezeigt, wie man mit find Dateien eines bestimmten Zeitraums finden kann. Da ich aber für die Archivierung keine Rekursion benötige, kann ich das Ganze etwas einfacher mit einem Einzeiler machen:

stat -c '%n Date:%y' * | perl -n -e 'print "$1
" if /^(.+)sDate:2008/' \n | zip archiv_2008.zip -@

Ich verwende hier stat, um das Ausgabeformat bestimmen zu können. Da die Dateinamen Leerzeichen enthalten können, kann ich keine Leerzeichen als Trenner zwischen Name und Datum verwenden, daher die Kennzeichnung mittels „Date:“. Perl filtert mir erstens alle Dateien von 2008 heraus und gibt auch nur den Dateinamen aus. Zip liest diese von der Standardeingabe, wenn die Dateiliste als -@ angegeben ist.

Soll Zip die Dateien auch gleich entsorgen, so kann man das über die Option -m erreichen.

Script-Fehler beim IE6 finden

Meldet der IE6 einen Javascript-Fehler, der sich im Firefox nicht nachvollziehen lässt, so wird es schwierig. Der IE6 meldet zwar, er hätte in der Datei xy.php in Zeile x bei Zeichen y einen Fehler gefunden, aber diese Angaben sind irreführend. Oder doch nicht? Wie man dem Fehler auf die Spur kommen kann zeige ich hier.

Beim Aufrufen einer Seite wird zum Beispiel die folgende Fehlermeldung angezeigt:

Screenshot der 1. Fehlermeldung

Im Prinzip ist die Angabe von Zeile und Spalte gar nicht so verkehrt, nur die Datei-Angabe stimmt meist überhaupt nicht, da eine HTML-Seite zum einen oft aus verschiedenen Teilen per PHP zusammengesetzt wird und zum anderen der Javascript-Code häufig in eigene Dateien ausgelagert ist.

Um nun herauszubekommen, in welcher Datei der Teufel im Detail steckt, muss man den Debug-Modus aktivieren und die Anzeige der Script-Fehler ausschalten. Dies geschieht in Extras » Internetoptionen » Erweitert. Dort werden, wie unten gezeigt, die Häkchen bei »Skriptdebugging deaktivieren« und bei »Skriptfehler anzeigen« entfernt. Danach muss der IE neu gestartet werden, damit die Änderungen wirksam werden.

Screenshot der Internetopionen des IE6

Wird nun die betreffende Seite erneut aufgerufen, sieht die Fehlermeldung etwas anders aus:

Screenshot der 2. Fehlermeldung

Hier ist nun auch erstaunlicher Weise von Zeile 14 die Rede! Klick man nun auf »Ja«, wird der IE-Debugger gestartet und die Datei geladen und angezeigt, in der der Internet-Explorer den Fehler gefunden hat. Der Cursor wird allerdings an die Position gesetzt, die in der ersten Fehlermeldung angezeigt wurde: Zeile 15, Spalte 22.

Ausschnitt der Debug-Anzeige

Wenn wir uns aber an die Angabe aus der zweiten Fehlermeldung (Zeile 14) erinnern und unser Augenmerk auf die Zeile über dem Cursor richten, sehen wir dort in Spalte 22 einen zweiten Punkt, der dort nicht hingehört. Dies ist der Fehler!

Das Verfahren ist etwas umständlich, aber immerhin zielführend. Und wenn man sich erst einmal daran gewöhnt bzw. damit abgefunden hat, ist es recht nützlich.

Leerzeichen bei For-In-Schleifen in der bash

Im Artikel Dateinamen mit Leerzeichen auf der Kommandozeile verarbeiten habe ich beschrieben, wie man Ärger mit Leerzeichen in Dateinamen umgeht. Heute geht es um Daten, die innerhalb einer For-In-Schleife aus einer Datei gelesen werden und die Leerzeichen enthalten.

Wenn wir eine Datei mit folgendem Inhalt haben:

klaus rechner1
martin rechner3
dieter rechner7

Und wir lassen diese von folgendem Script einlesen und wieder ausgeben (was natürlich recht sinnfrei ist, hier aber nur zur Veranschaulichung dienen soll):

#!/bin/bash
for ZEILE in `cat daten`
do
  echo $ZEILE
done

Dann kommt sowas raus:

klaus
rechner1
martin
rechner3
dieter
rechner7

Durch die Leerzeichen werden die Daten-Zeilen zerteilt. Damit das nicht passiert, setzt man den „Input Field Separator“ $IFS auf ‚
‚ (Standard ist ein “
„):

#!/bin/bash
Newline=$'
'
IFS=$Newline
for ZEILE in `cat daten`
do
echo $ZEILE
done
IFS=

Dann sieht das Ergebnis wie erwartet und gewünscht aus:

klaus rechner1
martin rechner3
dieter rechner7

Alle Fehlermeldungen in einem Script umleiten

Man kann in einem Shell-Script ja Ausgaben, die an den Standard-Fehler-Kanal STDERR gehen, mit 2>>dateiname.log in eine Datei umleiten. Dies muss aber für jeden Befehl einzeln gemacht werden. Es gibt aber bei der Bash eine Methode, die Umleitung für das gesamte Script zu machen.

Dazu nutzt man eine Spezialform des Befehls exec: Werden als Parameter nur Umleitungen angegeben, so leitet die Shell die gewünschten Kanäle permanent um.

#!/bin/bash
exec 2>> dateiname.log

echo "Normale Ausgabe"
echo "An stderr" >&2
echo "das folgende macht einen Fehler"
TEST=`gibtsnicht  `
echo "Das geht auch in Pipes:"
LINES=`lsx -1 $TREE | egrepx -v '^.+$' | wc -l`

Startet man das Script, so erhält man auf der Konsole diese Ausgabe:

Normale Ausgabe
das folgende macht einen Fehler
Das geht auch in Pipes:

Das sind die Ausgaben auf der Standard-Ausgabe.

Die Log-Datei enthält die Ausgabe der Fehlermeldungen:

An stderr
./logtest: line 7: gibtsnicht: command not found
./logtest: line 9: lsx: command not found
./logtest: line 9: egrepx: command not found

Sollen alle Ausgaben in die Logdatei umgeleitet werden, so verwendet man

exec >> dateiname.log 2>&1

SSH-Key auf einen anderen Rechner übertragen

SSH ist eine feine Sache, um sicher auf einen anderen Rechner zu zugreifen. Häufig wird jedoch die Passwortabfrage genutzt, die aber nicht so sicher und komfortabel wie Key-Methode.

Damit man diese aber nutzen kann, muss der Public-Key auf dem Zielrechner in die Datei authorized_keys eingetragen werden. Aber auch das lässt sich einfach und komfortabel per SSH machen:

cat ~/.ssh/id_dsa.pub | ssh user@zielrechner \n  "cd ~/.ssh && cat >> authorized_keys"

Nun wird man beim nächsten Login nicht mehr nach dem Passwort des Users auf dem Zielrechner gefragt, sondern nach der sog. Passphrase, also dem Passwort, mit dem der private Teil des oben übertragenen öffentlichen Schlüssels verschlüsselt ist.

um die Sicherheit weiter zu erhöhen, kann man nun den Zugang per Passwortabfrage verbieten, indem man in der sshd_config PasswordAuthentication no einträgt. Man sollte dann aber auch UsePAM no setzen, sonst hat PasswordAuthentication kein Effekt.

Sonderzeichen

copy_paste_character

Im Blog Webwork-Tools bin ich heute auf eine kleine aber feine Seite gestoßen: CopyPasteCharacter.com. Hier findet man die gebräuchlichsten Sonderzeichen, Ready for Copy & Paste. Man braucht die Zeichen auch gar nicht mit der Maus markieren – einfach draufgeklickt und schon ist das Zeichen in der Zwischenablage. Nie mehr umständliches Suchen „Sonderzeichen einfügen…“. So genial einfach, da hätte man eigentlich selbst drauf kommen können!

Außerdem gibt es noch HTML Entity Character Lookup. Hier gibt man einfach ein dem gesuchten ähnliches Zeichen ein und erhält eine Auswahl an Zeichen inkl. der Umschreibung als HTML-Entity. Und sowas braucht der Webworker schließlich fast täglich. Auch hier gibt es die Copy-to-Clipboard Funktion.

Mercurial Tipps & Tricks

Seit einiger Zeit bin ich auf das Verteilte Versionskontrollsystem Mercurial umgestiegen. Es bietet einige Vorteile gegenüber altbekannten Systemen wir z.B. CVS. Aber darauf will ich hier nicht eingehen, sondern einige Tipps und Tricks vorstellen, die den täglichen Umgang mit hg vereinfachen.

Push und Update des Ziels in einem

Mit hg push werden die Änderungen des eigenen Repositories in das Eltern-Repo hochgeladen. Dort werden die Änderungen aber nur im Repository eingetragen, das Arbeitsverzeichnis wird aber nicht aktuallisiert. Dies muss normalerweise per Hand mit einem hg update im entsprechenden Verzeichnis erfolgen. Beim Pull-Befehl gibt es den Schalter -u, der ein Update nach dem Pull ausführt – leider gibt es das nicht für das Push-Kommando.

Aber es gibt zwei Möglichkeiten, um diesen Schritt einzusparen (und vor Allem nicht zu vergessen):

Ausführen von Push und Update in einem Befehl

Man kann bei Linux & Co. die Ausführung von mehreren Kommandos auf einer Zeile bewirken, in dem man die Kommandos mit „&&“ verbindet. Außerdem kann man bei hg über den Parameter -R ein Repository angeben, in dem der Befehl ausgeführt werden soll. Somit lässt sich der Push und das Update des Ziel-Repositories verbinden:

  hg push && hg -R pfad_zum_ziel_repository update

Dazu muss man aber den Pfad des Ziels kennen. Dies lässt sich mit hg path ermitteln. Es spricht aber auch nichts dagegen, das direkt auf der Kommandozeile zu integrieren:

  hg push && hg -R `hg path | awk -F = '{ print $2; }'` update

Am Besten legt man sich einen Alias dafür an, in dem man z.B. folgendes in die .bashrc einträgt:

  pushup () { hg push && hg -R `hg path | awk -F = '{ print $2; }'` update ; }

Dann braucht man nur noch pushup eingeben, um ein Push mit nachfolgendem Update des Eltern-Repository zu machen.

Automatisches Update bei jedem Push

Unter 4.15. Any way to ‚hg push‘ and have an automatic ‚hg update‘ on the remote server? in den Mercurial-FAQs ist ein weiterer Weg beschrieben, wie man erzwingt, das bei einem Push auch ein Update des Ziels erfolgt. Dieses Verfahren hat aber aus meiner Sicht zwei Nachteile:

  1. Es wird immer ein Update gemacht, man kann es nicht „mal eben“ ausschalten. Bei der oben beschriebenen Lösung kann man immer den original hg push Befehl ausführen, wenn man gerade nicht will, dass ein Update durchgeführt wird.
  2. Die Änderung wirkt nur in dem Repository, in dem es in die hgrc eingetragen wurde. Arbeitet man in einem anderen Repository (z.B. eines anderen Projektes), in dem diese Änderung nicht durchgeführt wurde, kann das zu Verwirrungen führen, wenn man gewohnt ist, dass ein Push auch ein Update auslöst.

Die beschriebene Lösung über Hooks hat natürlich auch Vorteile (z.B. kann wirklich keiner das Update vergessen) und schlussendlich muss jeder selbst entscheiden, welchen Weg er beschreiten möchte.

Gibt es Unterschiede zwischen Repository und Working-Directory?

Klar, wenn man selbst Änderungen durchgeführt hat, kann man das über hg status erkennen. Was aber, wenn man ein hg pull oder ein hg push auf das Repository ausführt hat (Es kann ggf. auch jemand anderes ein Push auf „mein“ Repository gemacht haben, wenn er die Rechte dazu hat)? Dann hilft ein hg status nicht weiter. Ob es Unterschiede gibt, kann man aber mit

  hg diff -r tip

herausfinden. Will ich nur wissen ob und welche Dateien betroffen sind, verwende ich

  hg diff -r tip | grep '^diff'

Gibt es Änderungen im Eltern-Repository?

Auch hier gibt hg status keine Auskunft. Aber mit hg incoming (oder kurz: hg in erfahren wir, was es an Änderungen gibt, die bei einem Pull übertragen würden. Will ich wissen, welche Dateien sich ändern, setze ich den Schalter -v hinten an.

Ein Verzeichnis mit allen Unterverzeichnissen hinzufügen

Führt man hg add ./images/* aus, so werden nur die Dateien im Verzeichnis ./images hinzugefügt, nicht aber die Dateien, die sich in weiteren Unterverzeichnissen tummeln. Hier kann man sich mit find helfen:

  hg add `find ./images -type d -printf '%p/* '`

Firefox 3.0 – alles anders?

Firefox-Logo

Seit einiger Zeit ist der Firefox in der Version 3.0 veröffentlich. Nun habe ich es auch gewagt, von der 2.0 auf die neuste Version umzusteigen – und schon geht der Ärger los!

Man könnte fast behaupten, dass dies die unausgereifteste Release ist, seit ich Mozilla oder Firefox benutze – und das ist schon verdammt lange. Unter Windows und aktuellen Linux-Distros lässt er sich noch problemlos installieren, aber bei älteren Linux-Versionen muss man wohl bei der 2.0er bleiben, da dort diverse Bibliotheken fehlen und es bislang keinen Build mit statisch gelinkten Bibliotheken gibt.

Ein recht einfach zu behebendes Problem ist die Tatsache, dass auch in der deutschen Version des freien Browsers die Google-Suche auf google.com eingestellt ist und man somit keine deutschen Ergebnisse bekommt. Zum Glück gibt es unter http://mycroft.mozdev.org/google-search-plugins.html jede Menge Search-Engine-Plugins, darunter auch „Google DE – Das Web“, „Google DE – Seiten auf Deutsch de-DE“ usw. (Hinweis zuerst gefunden im Blog von Felix Wunderwald)

Ein Aufreger ist auch, dass es wohl Probleme mit dem DOM-Inspector beim Update unter Windows gibt. Will man ihn benutzen, bekommt man die Meldung, er sei nicht installiert oder deaktiviert. Ich hatte ihn jedoch installiert – zumindest hatte ich „Benutzerdefiniert“ gewählt. Allerdings wurde ich nicht nach weiteren Einstellungen gefragt… Folgt man dem Link in der Fehlermeldung, so bekommt man den Hinweis, man müsse als Abhilfe den Browser wieder deinstallieren, das übrig gebliebene Verzeichnis löschen und dann die Installation erneut durchführen. Das klappt, auch wenn man wiederum nicht nach den benutzerdefinierten Einstellungen gefragt wird – und man danach wieder sämtliche Plugins wie den Flashplayer usw. neu installieren darf!

Ein weiters Ärgernis, für dass ich noch eine Lösung oder die Ursache finden muss: Unter Windows fragt der FF beim Schließen jetzt, ob die zzt. geöffneten Tabs beim nächsten Mal wieder hergestellt werden sollen. Unter Linux gibt es diese Frage nicht, hier sieht man leider noch das alte Verhalten.

Dies ist sicher nicht das Ende der Fahnenstange. Wenn ich den 3.0er weiter benutze, werden mir sicher noch weiter Unannehmlichkeiten auffallen. Eines steht jetzt jedoch schon fest: Mit dem anscheinend etwas übereilten Release hat sich die Firefox-Gemeinde keinen Gefallen getan.

Rechnernamen mir der TLD .local können nicht aufgelöst werden

Das Problem: Verwendet ein lokales Netzwerk die Domain .local kann ein neuerer Linux-Client die lokalen Namen nicht auflösen.

Der Grund: .local wird Zeroconf-Diensten wie z.B. Rendezvous verwendet. Zeroconf ist eine Technik zur konfigurationsfreien Vernetzung von Geräten in lokalen Rechnernetzen.
Neuere Linux-Distributionen sind darauf vorbereitet und senden DNS-Anfragen für Adressen mit der Top-Level-Domain per Multicast an den Port 5353 (mdns) der Adresse 224.0.0.251.

In Wikipedia gibt es einen Artikel zu Zeroconf, der die Hintergründe beschreibt. U.a. ist dort zu lesen:

Alle DNS-Abfragen für Namen, die auf .local enden, müssen mit UDP und IP Multicast an die mDNS-Multicast-Adresse 224.0.0.251 Port 5353 gesendet werden.

Und weiter ist zu lesen:

Natürlich kann es in der Praxis zu Konflikten kommen, von den Erfindern von mDNS wurde das aber als sehr unwahrscheinlich angenommen.

Dummerweise wird die TLD .local recht häufig verwendet – bei der IETF existiert sogar ein Draft, (http://www.ietf.org/proceedings/99nov/I-D/draft-ietf-dnsind-local-names-07.txt), in dem die Verwendung der Top-Level Domain „.local“ im Intranet vorgeschlagen wird, speziell wenn der lokale Adressbereich nach RFC1918 zum Einsatz kommt.

Die Lösung: Auch diese findet sich im o.g. Wikipedia-Artikel:

Damit unter Linux die Namensauflösung bei der Top-Level-Domain .local wie gewohnt über den DNS-Server (z. B. Bind) abgewickelt wird, ist der Eintrag mDNS off in der Datei /etc/host.conf erforderlich.

Bei neueren (SuSE-)Distributionen funktioniert das aber nicht mehr, da /etc/host.conf ignoriert wird. Stattdessen muss die Datei /etc/nsswitch.conf bearbeitet werden. Dort findet sich eine Zeile

hosts: files mdns4_minimal [NOTFOUND=return] dns

die wieder in die alte Form

hosts: files dns

geändert werden muss.

Weitere Links zum Thema: