Weiter zum Inhalt

bash – Spaces in Dateinamen ersetzen

Auf der Suche nach einer Methode in mehreren Dateien gleichzeitig die Spaces durch Underscores zu ersetzen bin ich auf stackoverflow fündig geworden.

Das ganze mit zwei Parametern versehen und in eine Bash Funktion gepackt sieht bspw. so aus:

function s2d() {
    [[ -z "$1" ]] && f="* *" && p='.'
    [[ -n "$1" && -z "$2" ]] && p=$1 && f="* *"
    [[ -n "$1" && -n "$2" ]] && p=$1 && f=$2
    find "${p}/" -depth -name "${f}" -execdir rename 's/ /_/g' {} \;
}

Funktioniert mit den meisten Linux Distributionen vermutlich prima. Unter Mac OS X musste ich allerdings erst noch rename nachinstallieren, damit das auch funktioniert. Runterladen kann man das bei cpan.org. Auspacken und anständig installieren und schon läuft es auch auf dem Mac.

bash Kommando zum Auflisten des Verzeichnisbaums

Auf der Suche nach einer Möglichkeit den Verzeichnisbaum unterhalb eines bestimmten Verzeichnisses aufzulisten bin ich hier auf gleich zwei schöne Möglichkeiten gestolpert:

ls -R | grep ":$" | sed -e 's/:$//' -e 's/[^-][^\/]*\//--/g' -e 's/^/ /' -e 's/-/|/'

und

find ./ -type d | sed -e 's/[^-][^\/]*\//--/g;s/--/ |-/'

Die zweite Variante habe ich mir in eine Bash Funktion in meiner .bashrc gepackt und noch einen Parameter hinzugefügt, dass ich das Ausgangsverzeichnis einfach mitgeben kann und nicht erst in das Verzeichnis wechseln muss:

function tree() {
    [[ -z "$1" ]] && p='.' || p=$1
    find ${p} -type d | sed -e 's/[^-][^\/]*\//--/g;s/--/ |-/'
}

Damit habe ich die tree Funktion immer dabei und bekomme z.B. mit

# tree /etc/apache2

die folgende Ausgabe:

 |---apache2
 |-----extra
 |-----original
 |-------extra
 |-----other
 |-----users

Zimbra – Liste aller Account Aliases auf der Kommandozeile

Im Zimbra Forum gibt es einen Post von PhilF, mit einem kleinen Skript, das auf der Kommandozeile eine Liste mit allen Account Aliases ausgibt. Komischerweise geht das bisher nicht mit Zimbra Mitteln. Mit dem Einzeiler

zmprov  sa  -v '(|(objectClass=zimbraDistributionList)(objectClass=zimbraAccount))' \
    | egrep '^(# name |# distributionList|zimbraMailAlias)' \
    | cat -s  \
    | sed 's/^zimbraMailAlias:/     /; s/^# name /\nMailbox: /; s/^cn: /Name: /; s/^# distributionList /\nMailingList: /' > /tmp/alias.list

bekommt man etwas schmucklos die Liste inklusive der Verteilerliste. Deutlich schöner und aufgeräumter ist das mit Phils Skript:

(
  echo Listing mailbox aliases....  >&2
  echo
  echo "==================== Mailbox Aliases ========================"
  echo
 
  zmprov sa -v '(objectClass=zimbraAccount)' | perl -ne \
     '
       if ( s/^# name /\nMailbox: /  or
            s/^cn: /Name: /        or
            s/^zimbraMailAlias:/    / ) { print $_; }
     '
 
  echo Listing distribution list aliases....  >&2
  echo
  echo
  echo "==================== Distribution List Aliases ========================"
  echo
 
  zmprov  sa  -v "(objectClass=zimbraDistributionList)"  | perl -ne \
     '
       if ( s/^# distributionList /\nMailingList: /  or
            s/^cn: /Name: /        or
            s/^zimbraMailAlias:/    / ) { print $_; }
     '
) > /tmp/alias.list
 
echo
echo " -- The list of aliases is now stored in /tmp/alias.list"
echo

Um Phil vollständig zu zitieren: Für das und ggf. weitere Skripte muss man nur einen Ordner anlegen, bspw.

/opt/zimbra/scripts

und darin eine Datei

listAlias

anlegen, den Code oben reinkopieren und diese mit

chmod +x listAlias

ausführbar machen. Mit dem Aufruf

/opt/zimbra/scripts/listAlias

erhält man unter

/tmp/alias.list

die aktuelle Liste der Account Aliases und Verteilerlisten. Danke an PhilF, hat mir wirklich geholfen.

Proxy in CPAN einstellen

Immer wieder stehe ich vor dem gleichen Problem, wenn ich auf einem neuen Server Perl Module mit cpan installieren will. Ich bekomme keine Verbindung zu den Installationsservern, da cpan nichts von unserem Proxy weiß. Meine bash Umgebung ist gut konfiguriert, deshalb kann ich mir mit

env | grep -i proxy

den Proxy anzeigen lassen. Und damit kann ich dann wieder cpan meine Proxy Einstellungen beibringen:

# cpan
cpan[1]> o conf init /proxy/
 
If you are accessing the net via proxies, you can specify them in the
CPAN configuration or via environment variables. The variable in
the $CPAN::Config takes precedence.
 
Your ftp_proxy? [] ftp://proxy:8080
 
Your http_proxy? [] http://proxy:8080   
 
Your no_proxy? []
 
If your proxy is an authenticating proxy, you can store your username
permanently. If you do not want that, just press RETURN. You will then
be asked for your username in every future session.
 
Your proxy user id? [] 
 
Please remember to call 'o conf commit' to make the config permanent!
 
cpan[2]> o conf commit
commit: wrote '/usr/lib/perl5/5.10.0/CPAN/Config.pm'

Das war’s. Natürlich muss der Proxy entsprechend angepasst werden, er wird sicherlich nicht immer proxy:8080 heißen.

ssh Schlüssel übertragen

Nachdem ich hier einen schönen Einzeiler gefunden habe, um meinen ssh Schlüssel auf einen Server zu kopieren habe ich mir noch einen kleinen Check geschrieben, damit nicht mehrfach der Schlüssel kopiert wird. Das hat mich auch an ssh-copy-id gestört.

user=$1
hostname=$2
ssh_key=`cat ~/.ssh/id_rsa.pub`
 
echo "Copying ssh key to host"
ssh="ssh -l $user $hostname"
echo $hostname
echo "$ssh '-o PreferredAuthentications=publickey ls > /dev/null '"
$ssh -o PreferredAuthentications=publickey "ls > /dev/null"
if [[ $? -eq 0 ]];then
    echo 'public key already on host'
else
    echo 'copying public key to host'
    $ssh "mkdir -p -p 700 ~/.ssh/; echo $ssh_key >>  ~/.ssh/authorized_keys"
fi

Auf der Kommandozeile ein entsprechendes Skript copy_ssh_id einfach mit Benutzernamen und Servernamen als Parameter aufrufen.

Quote of the week

Mann, ist die VNC-Verbindung langsam. Alles Scheiße außer Putty!

- R.B. am Donnerstag :-)

Python: Dateien und/oder Verzeichnisse kopieren

Eine schöne und einfache Methode, um mit Python Verzeichnisse und/oder Dateien zu kopieren habe ich bei stackoverflow gefunden:

import shutil, errno
 
def copyanything(src, dst):
    try:
        shutil.copytree(src, dst)
    except OSError as exc: # python >2.5
        if exc.errno == errno.ENOTDIR:
            shutil.copy(src, dst)
        else: raise

Das ist hilfreich, wenn vor dem Kopieren nicht bekannt ist was genau kopiert wird. Im ersten Kommentar zu dieser Antwort wird vorgeschlagen mit

os.path.isdir(src)

einfach vorher zu prüfen, ob es sich um ein Verzeichnis handelt, aber die obige Lösung ist der pythonic way dieses Problem zu lösen.

Radiant updaten

Das Update von meiner Radiant Seiten mit der Version 0.8.1 (gem) zu 0.9.1 (gem) war unkompliziert. Das Backup-Skript anwerfen, das die Seiten und die zugehörigen Datenbanken sichert und dann mit

gem update radiant

die neuste Version des gems holen. Dann für jede Seite

cd <meine_seite>
rake radiant:update
RAILS_ENV=production rake db:migrate

durchführen und schon schnuckelt alles wieder.

Erste Schritte mit dem Radiant CMS

Radiant ist ein meiner Meinung nach sehr schönes CMS (=Content Management System), weil es von Haus aus erst einmal sehr wenige Einstellungsmöglichkeiten gibt und man recht schnell loslegen kann. Andererseits sollte man zumindest in etwa wissen was man tut und mindestens Grundkenntnisse in (x)html und css haben. Dann hat man aber wie gesagt ein schönes CMS, in das man prima seine xhtml/css-Templates packen kann.

Leider ist die Dokumentation von Radiant nicht wirklich ausführlich und nicht immer hilfreich. Vor allem bei den ersten Schritten hat sie mir kaum weiter geholfen. Auch sonst habe ich nicht viel gefunden. Die wichtigsten Links sind hier und hier gesammelt. Deshalb will ich hier einmal zusammenfassen, wie ich mir das Arbeiten mit Radiant etwas leichter gemacht habe.
Ruby und die Rubygems hatte ich sowieso schon installiert, also konnte ich direkt mit

sudo gem install radiant

Radiant installieren. Ein neues Projekt kann man dann einfach mit

radiant mein_projekt -d sqlite3

anlegen. Sqlite3 als Datenbank reicht für ein Testprojekt aus. Die nächsten Schritte bekommt man direkt angezeit.

cd mein_projekt
rake production db:bootstrap

Die erste Frage mit y beantworten und dann Daten für den Administrator eingeben. Für das DB-Template wählt man 1 - Empty aus. Die drei anderen DB-Templates sind Beispielseiten, die zeigen, was man mit Radiant machen kann. Deshalb habe ich mir ein Verzeichnis radiant_demos angelegt und dort die Schritte von oben für alle drei Templates wiederholt. Die drei Seiten sind prima, um zu sehen wie die grundlegenden Schritte in Radiant aussehen sollen und dienen also sowohl als Spickzettel als auch als gutes Beispiel.

Um nicht immer den Server stoppen und neu starten zu müssen, um zwischen den Seiten hin und her zu schalten starte ich sie auf verschiedenen Ports:

mein_projekt/script/server -e production
radiant_demos/roaster/script/server -e production -p 3001
radiant_demos/simple_blog/script/server -e production -p 3002
radiant_demos/styled_blog/script/server -e production -p 3003

So kann ich im Browser unter http://localhost:3000 bis http://localhost:3003 meine vier Seiten finden.

Datei- und MySQL-Recovery nach Servercrash

Wenn das letzte Backup schon deutlich zu alt kommt für den entsprechenden Server die ideale Zeit zum kaputt gehen. Vorzugsweise durch einen Plattencrash oder ähnlichen Spaß, so dass sich das Linux des Servers nur noch im Recovery Modus starten lässt. Services hochfahren oder das längst fällige Backup anzustarten sind keine Optionen mehr. Was tun?

Ganz pauschal und einfach lässt sich das natürlich nicht beantworten. Alles wird man z.B. bei einem Plattencrash nicht wieder bekommen, aber vielleicht genug, um den Server wieder aufsetzen zu können. Dafür gibt es natürlich viele Möglichkeiten. dd_rescue zum Beispiel. Hier gibt es eine Anleitung für Debian basierte Systeme.

Eine etwas simplere (und vielleicht auch naivere) Herangehensweise die oft auch zum Ziel führt versuche ich hier kurz zu beschreiben. Es wird sicher nicht alles wiederhergestellt werden können, ich übernehme keine Garantie dafür, dass überhaupt etwas wiederhergestellt wird. Aber ich denke, dass es je nach Situation einen Versuch wert sein kann.

Auch im Rescue System lassen sich die beschädigten Platten evtl. noch mounten. Wenn das klappt versucht man erstmal selektiv alle wichtigen Dateien zu sichern. Natürlich nicht einfach mit einem cp in ein anderes Verzeichnis auf der kaputten Platte, sondern am besten per rsync und ssh auf einen anderen Rechner:

rsync -av /mnt/pfad user@meinNeuerServer:/sicherungspfad

Damit lassen sich z.B. die Dateien aus /var/www/meineSeite oder /var/www/meinBlog sichern (für den rsync Aufruf dem Pfad natürlich ein /mnt voranstellen). Mit etwas Glück bekommt man so den Teil seiner Seite, der nicht in einer Datenbank liegt schnell wieder. Evtl. einfach die Dateien aus dem neusten Update drüber bügeln und dieser Teil der Seite ist schnell wieder hergestellt. Ohne die Daten aus der Datenbank ist das natürlich aber noch nicht viel Wert, sondern erspart höchstens etwas Arbeit, denn drupal oder einen WordPress Blog hat man auch von Hand schnell wieder aufgesetzt.

Also, wie bekomme ich die Daten aus meiner MySQL Datenbank wieder, wenn ich mysql nicht mehr starten kann? Eine Antwort habe ich u.a. hier gefunden. Die Dateien einer MySQL Datenbank liegen im Verzeichnis /var/lib/mysql/<db_name>. Wenn auf dem neuen Server schon mysql installiert ist, kann man direkt wieder ein rsync Kommando absetzen:

rsync -av /mnt/var/lib/mysql/&lt;db_name&gt; user@meinServer:/var/lib/mysql/

Mit etwas Glück wird vieles oder alles kopiert. Kaputte Sektoren auf der Platte bedeuten ja nicht unweigerlich, dass die gesamte Platte nicht mehr gelesen werden kann.

Auf dem neuen Server müssen noch ein paar kleine Schritte getan werden, bevor man testen kann, ob es wirklich funktioniert hat:

1. Die Besitzer der Datenbank Dateien anpassen:

chown -R mysql:mysql /var/lib/mysql/&lt;dbname&gt;

2. Mit der Datenbank verbinden und die Tabellen einzeln checken und ggf. reparieren und den alten Datenbank Benutzer wieder anlegen:

mysql -u user -p
USE &lt;db_name&gt;;
 
SHOW TABLES;

Für jede Tabelle in der Liste check table ausführen:

CHECK TABLE &lt;tabellenname&gt;;

Hiervon bekommt man entweder OK oder please run repair table `<tabellenname>` als Antwort. Im zweiten Fall führt man das auch aus:

repair TABLE `&lt;tabellenname&gt;`;

Am Schluss noch den alten Benutzer wieder anlegen, bevor man den Browser auf den neuen Server loslässt und schaut, ob die Seite wieder läuft:

GRANT ALL privileges ON &lt;tabellenname&gt;.* TO 'benutzer'@'localhost' IDENTIFIED BY 'tollesPasswort' WITH GRANT OPTION;

Mit etwas Glück funktioniert die Seite danach wieder wie gewohnt auf dem neuen Server. Wenn das alles nichts geholfen hat bleibt der Versuch mit dd_rescue oder eben man packt das letzte (wenn auch evtl. alte) Backup auf den neuen Server und kann zumindest für einige der Inhalte den google Cache bemühen.