Schlagwort-Archive: Linux

Skip der ersten Zeile wenn leer

Heute hatte ich das Problem, eine leere Ausgabe des Programms „zip“ zu unterdrücken, damit Cron mir keine Mail schickt, wenn es nichts zu zippen gibt.

Findet zip nichts, was es einpacken kann, bekommt man die folgende Meldung:

/usr/bin/zip -r /tmp/test.zip . -t `date -d "-1 days" +%Y-%m-%d` -i "*/bearbeitet/*"

zip error: Nothing to do! (/tmp/test.zip)

Die Zeile mit „Nothing to do!“ lässt sich ja noch einfach mit einem grep unterdrücken, aber wie werde ich die Leerzeile davor los? Ein

| tail +2

bewirkt zwar, dass die Ausgabe erst ab der zweiten Zeile erfolgt – leider auch dann, wenn zip etwas zu tun bekommt. Also muss perl ran:

more testdaten | perl -n -e 'print $_ unless ( $. == 1 && /^$/ )'

Dies unterdrückt die erste Zeile nur, wenn sie leer ist, wobei weitere Leerzeilen nicht ausgefiltert werden.

Der ganze Aufruf sieht dann so aus:

/usr/bin/zip -r /tmp/test.zip . -t `date -d "-1 days" +%Y-%m-%d` -i "*/bearbeitet/*" 2>&1 | \n  perl -n -e 'print $_ unless /zip error: Nothing to do/ || ( $. == 1 && /^$/ )'

STDERROR in eine Variable umleiten

In einem Script verkette ich mehrere Befehle, was aber den Nachteil hat, dass sich für die Fehlerbehandlung nur der Exit-Wert des äußeren Befehls auswerten lässt. Hier die Zeile, um die es geht:

sudo -u backup ssh root@${RECHNER} "~/sbin/do_SSHbackup" > $BACKUPDIR/${RECHNER%%.*}/${AKTDATE}.tgz || OK=NOK

Hier wird die Variable OK nur auf NOK gesetzt, wenn z.B. sudo fehlschlägt oder das Zielverzeichnis nicht existiert. Wirft jedoch das per SSH aufgerufene Script do_SSHbackup einen Fehler, so bekommt die Variable OK nichts davon mit. Auf dem Standardfehlerkanal landet jedoch eine Fehlermeldung.

Wenn ich nun die Ausgabe der Fehlermeldungen in einer Variablen sammeln und diese auswerten könnte, wäre ein Abfangen des Fehlers möglich. Aber wie, ohne dabei den Standardausgabekanal zu beeinflussen? Nach ein wenig „Googleei“ fand ich die Lösung bei stackoverflow.com.

OUTPUT=$( { sudo -u backup ssh root@${RECHNER} "~/sbin/do_SSHbackup" > $BACKUPDIR/${RECHNER%%.*}/${AKTDATE}.tgz; } 2>&1 ) || OK=NOK

Somit bekomme ich alle Fehlermeldungen in die Variable OUTPUT, welche ich im Nachgang auswerten kann:

if [ "$OK" != "OK" -o -n "$OUTPUT" ] ; then
  echo "$OUTPUT">&2
  ...
fi

Adobe-Reader Installationsdateien

Die Links zur Installation des (Acrobat) Adobe Reader, die man so im Netz findet, führen alle zur Adobe-Seite und dort zu einem Installer, der die eigentliche Installation aus dem Netz nach lädt. Das nützt einem aber nichts, wenn man den Reader auf einem Rechner installieren will, der gar keinen Zugang zum Internet hat.

Aber bei chip.de findet sich in den Kommentaren der Hinweis auf ftp://ftp.adobe.com/pub/adobe/reader/win/. Hier gibt es aktuelle und ältere Versionen des Windows-Installers zum Download. Installer für andere Betriebssysteme (z.B. Linux, Mac) findet man unter ftp://ftp.adobe.com/pub/adobe/reader/.

krdc: RDP mit Domänen-Angabe

Bei KDE gibt es ja auch krdc, den „Verbindungsclient zu Fremdrechner“, mit dem man sich wunderbar per Remote-Desktop-Protokoll (RDP) auf Windows-Rechner verbinden kann. Ich nutze das täglich, u.a. wegen des guten Vollbild-Modus. Der ist nämlich beim Kommandozeilen-Tool rdesktop leider nicht so gut. Dafür hat rdesktop eine Option -d, mit der man die Windows-Domäne angeben kann.

Aber man kann das auch mit krdc erreichen in dem man die Domäne vor den Benutzernamen stellt und beide Teile durch zwei Backslashs trennt:

krdc --fullscreen rdp://Domaene\klaus.meier@192.168.1.2

Will man das in einem Desktop-Icon eintragen, so muss man die beiden Backslashs verdoppeln, hat dann also vier davon:

Exec=krdc --fullscreen rdp://Domaene\\klaus.meier@192.168.1.2

Dateien mit Sym- oder Hardlinks finden

Symlinks finden

Das Verlinken von Dateien oder Verzeichnissen per Symlink ist eine prima Sache. Schwierig wird es nur, wenn man Dateien löscht oder verschiebt, auf die Symlinks zeigen. Diese laufen dann nämlich ins Leere. Um zu prüfen, ob es Symlinks auf eine Datei oder ein Verzeichnis gibt, nutz man das folgende Kommando:

find / -type l -print | xargs ls -ld | grep 'dateiname'

Das kann ich auch verwenden, wenn ich z.B. ein Verzeichnis verschieben will und nicht weiß, ob es Links auf Dateien oder Unterverzeichnisse im fraglichen Verzeichnis gibt. Ich setze dann als ‚dateiname‘ den Namen des Verzeichnisses ein, das ich verschieben will.

Siehe auch http://www.grymoire.com/Unix/Find.html#uh-6

Hardlinks finden

Mitunter benutzt man auch Hardlinks, um Dateien zu verlinken (z.B. Backup mit rsync, wie in der c’t 07/2009, S. 212 beschrieben). Hat man nun eine Datei, bei der man anhand des Linkcount erkennt, dass sie Hardlinks hat, will man evt. auch wissen, wo die anderen Links liegen. Mit

find . ! -type d -links +1 -ls|sort -n

findet man alle Dateien, deren Linkcount größer 1 ist. Durch die Sortierung anhand des Inodes (erste Spalte) kann man gut zusammengehörende Dateien erkennen.

Will man für eine Bestimmte Datei die zugehörigen Links finden, geht das auch so:

f=`ls -i dateiname |awk '{print $1}'`
find / -inum $f

Siehe auch: The UNIX and Linux Forums: search for hardlinks based on filename via find command.

Videos der ZDF-Mediathek mit Linux speichern

Dieser Tage lief wieder ein sehr interessanter Beitrag im ZDF, den ich leider aus zeitlichen Gründen nicht sehen konnte. Zum Glück konnte ich ihn zwei Tage später in der ZDF-Mediathek finden. Aber leider ruckelte der Stream sehr stark, so dass ich ihn so nicht sehen wollte. Nach einiger Recherche im Netz und ein paar nicht so erfolgreichen Versuchen, den Stream mit dem VLC zu speichern, fand ich meine Lösung in einem Blog-Artikel von Stefan Waidele.

Hier die Kurzfassung:

  1. Beitrag in der Mediathek finden.
  2. Oben rechts auf die HTML-Version wechseln und dann den 2000er Mediaplayer-Link kopieren.
  3. Den kopierten Link in den folgenden Einzeiler einbauen, warten, fertig!
curl VIDEO-URL | grep mms: | cut -d " -f 2 | xargs -n1 mplayer -dumpstream -dumpfile DATEINAME.wmv

Zum Betrachten muss man nicht zwangsläufig den MPlayer benutzen, das geht dann auch wieder mit dem VLC.

Sicherlich kann man zum Aufzeichnen auch den VLC benutzen, aber ich hatte bislang weder die Zeit noch die Lust, mich mit den vielen und verwirrenden Kommandozeilen-Optionen des VLC auseinander zu setzen. Aber vielleicht hat ja jemand einen Tipp.

set -x Ausgaben nur in eine Datei schreiben

Der Schalter set -x (auch xtrace genannt) ist ein hilfreiches Werkzeug zum Debuggen von Shellskripten. Aber manchmal sieht man auf Grund der Vielzahl an Meldungen den Wald von lauter Bäumen nicht. Und der normale Anwender sollte davon besser auch nichts zu sehen bekommen. Daher sollte man nach getaner Kammerjägerei den Schalter wieder aus dem Skript entfernen oder auskommentieren.

Was aber, wenn man die schönen Meldungen auch in der normalen Anwendung sammeln möchte, um z.B. einem von einem Anwender gemeldeten Fehler auf die Spur zu kommen. Mit ein paar zusätzlichen Zeilen kann man dies bewerkstelligen.

Hier erst mal das „normale“ Script:

#!/bin/sh

echo "Ich melde einen Fehler" >&2
echo "Eine ganz normale Meldung"

Es macht nichts wirklich sinnvolles, es gibt nur eine Meldung auf STDERR und eine auf STDOUT aus.

Nun die modifiziere Variante:

#!/bin/sh
{
  echo "+++++++++ `date "+%F %T"`: ${0##*/} $1 $2 $3 +++++++++"
  set -x
  echo "Fehler" >&2
  echo "normal"
  set +x
} 2>&1 | tee -a /tmp/${0##*/}.log | grep -v '^+'

Dieses Skript schreibt die komplette Ausgabe (mit den Debug-Zeilen von xtrace) in eine Logdatei mit gleichen Namen wie das Script selbst (mit angehängtem .log) in das Verzeichnis /tmp. Die xtrace-Zeilen werden für die normale Ausgabe über grep ausgefiltert.

Durch den Schalter -a bei tee wird die Ausgabe immer an die bestehende Logdatei angehängt. Dem trägt auch die echo-Zeile Rechnung, durch die zum Einen der Beginn eines neuen Laufs markiert wird und zum Anderen die zusätzlichen Parameter protokolliert werden.

Firefox 3.6 und Java auf SuSE 11.1

Ich habe Anfang dieser Woche auf meinem Laptop den Firefox auf die Version 3.6 gebracht. Abgesehen von einem Addon, das den Browser zum unregelmäßigen Absturz brachte (ich hab noch nicht raus, welches Addon es ist – zzt. sind die meisten deaktiviert) funktionierte auch Java nicht mehr mit dieser Version.

Nach stundenlangem Googlen und Ausprobieren hab ich es nun endlich wieder am Laufen! Die Lösung ist eigentlich ganz einfach: ich musste einen Symlink von /usr/lib64/jvm/java-1.6.0-sun-1.6.0/jre/lib/amd64/libnpjp2.so in mein Mozilla-Plugin-Verzeichnis ~/.mozilla/plugins anlegen und den Browser neu starten. Das Plugin-Verzeichnis musste ich aber erst noch erstellen.

Diesen entscheidenden Hinweis fand ich per Google auf der Seite „Camp Firefox • Thema anzeigen – FF 3.6 Java Plugin“ — allerdings ist diese Seite zzt. nicht erreichbar, so dass ich den Google-Cache bemühen musste.

Die o.g. Datei stammt aus dem Paket java-1_6_0-sun-plugin-1.6.0.u17-1.20. Dieses wiederum hatte ich in meiner Verzweiflung per One-Click-Install aus dem Non-OSS openSUSE Factory-Repository geholt, aber das Standard-Paket 1.6.0.u17-1.1.1 sollte m.E. auch gehen.

Da ich bei der ganzen Herumprobiererei auch die aller-aktuellste JRE-Version von Sun heruntergeladen und installiert hatte und mich die Plugin-Testseite auch darauf aufmerksam gemacht hatte, dass es eine neuere Version des Plugins geben soll, haben ich den Link noch mal auf eben jene aktuelle Version geändert:

libnpjp2.so -> /usr/java/latest/lib/amd64/libnpjp2.so

Das funktioniert auch un die Testseite ist nun vollständig zufrieden.

Eine Reihe von IP-Adressen per Ping prüfen

Mitunter hat man das Problem, eine nicht kleine Anzahl an Rechnern auf Erreichbarkeit zu überprüfen. Die Adressen und Hostnamen liegen als Excel-Liste vor, aber diese alle von Hand zu pingen … dazu bin ich echt zu faul. Also habe ich mir ein kleines Script gebaut, welches diese Aufgabe elegant erledigt:

#!/bin/sh
#
# Sendet einen Ping an alle in der übergebenen Datei aufgeführten Adressen.
# In der Liste muss pro Zeile zuerst die IP-Adresse und danach durch Leerzeichen
# getrennt der Hostname stehen (optional).
# Die Ausgabe von Ping kann unterdrückt werden, indem STDERR ins Null-Dev
# geschickt wird:
# ping_list liste.txt 2>/dev/null
#

#set -x

Newline='
'

IFS=$Newline
for LINE in `cat $1`
do
  #echo "'$LINE'"
  ADR=${LINE%% *}
  HOST=${LINE##* }
  #echo "Adr: $ADR"
  #echo "Host: $HOST"
  if [ "$OSTYPE" = "linux" ]
  then
    ping -q -W 3 -c 1 $ADR 1>&2
  elif [ "$OSTYPE" = "hpux11.00" ]
  then
    ping $ADR -n 1 -m 3 1>&2
  else
    echo "Unknown OS"
    exit 99
  fi
  if [ $? -eq 0 ]
  then
    echo "$ADR ($HOST) is up"
  else
    echo "$ADR ($HOST) FAILED"
  fi
done
IFS=

Es arbeitet zzt. unter Linux (SuSE 11.1) und HP-UX 11i und kann auch hier heruntergeladen werden:
ping_list

munin auf centOS 5.2 installieren

Ich war kürzlich in der Verlegenheit, ein System mit centOS 5.2 überwachen zu müssen. Ich habe mir als Tool dazu munin auserkoren, das sich an Hand der Anleitung „Überwachung eines CentOS 5.2 Servers mit munin und monit“ einfach installieren und in Betrieb nehmen lässt (auf monit habe ich verzichtet).

Allerdings bekam ich danach alle fünf Minuten eine E-Mail mit der Meldung:

Pango-WARNING **: Invalid UTF-8 string passed to pango_layout_set_text()

Zunächst habe ich alle relevanten Dateien in /etc/munin mittels iconv von ISO nach UTF8 konvertiert – was nichts genützt hat, da die Dateien bereits in UTF8 sind bzw. keine Umlaute etc. enthalten.

Eine weitere Recheche im Netz der Netze brachte mich auf ein Post im Gentoo-Forum, in dem ein Patch auf die Datei munin-graph erwähnt wird. Dieser Patch ist leider für die Munin-Version 1.3.4, auf meinem System ist aber die Stable-Version 1.2.5 installiert. Ich habe mir aber einmal den Patch angesehen und festgestellt, dass er recht einfach ist. Er baut  an sich nur eine Erkennung ein, ob die verwendete RRD eine Version größer oder gleich 1.3. Nur dann werden die an RRD übergebenen Parameter nach UTF8 gewandelt. Netterweise war der Patch im Context-Format erstellt worden, so dass es mir ein Leichtes war, die entsprechenden Code-Stellen auch in der Datei /usr/share/munin/munin-graph der Version 1.2.5 zu finden. Ich habe die beiden Code-Fragmente an den entsprechenden Stellen eingebaut – und es geht!

Hier nun der entsprechend angepasste Patch für die Munin-Version 1.2.5:

*** munin-graph.old     2009-03-25 01:28:10.000000000 +0100
--- munin-graph 2009-10-01 15:42:36.000000000 +0200
***************
*** 29,34 ****
--- 29,35 ----
  use Digest::MD5;
  use Getopt::Long;
  use Time::HiRes;
+ if ($RRDs::VERSION >= 1.3) { use Encode; }

  my $graph_time= Time::HiRes::time;
  my $DEBUG = 0;
***************
*** 832,837 ****
--- 833,848 ----
                    push @complete, "--end",(int($lastupdate/$resolutions{$time}))*$resolutions{$time};
            }
            print "

rrdtool "graph" "", join (""
	"",@complete), ""
" if $DEBUG;
+
+           # Since version 1.3 rrdtool uses libpango which needs its input
+           # as utf8 string. So we assume that every input is in latin1
+           # and decode it to perl's internal representation and then to utf8.
+           if ( $RRDs::VERSION >= 1.3 ) {
+               @complete = map {
+                   $_ = encode("utf8", (decode("latin1", $_)));
+               } @complete;
+           }
+
            RRDs::graph (@complete);
            if (my $ERROR = RRDs::error) {
                logger ("Unable to graph $filename: $ERROR");

Den Patch gibt es natürlich auch zum Download: munin-1.2.5_utf8.patch