Skip to content

Tip #14: E-Mails mit mutt automatisch verschlüsseln

Ich sinniere schon seit einiger Zeit, wie ich ausgehende E-Mails weitgehend automatisch verschlüsseln kann. Vor längerer Zeit stiess ich dabei auf das Perlskript von Martin Grandrath. Auf der Seite ist gut beschrieben, wie das einzurichten ist. Das problem am Skript ist die relativ lange Startzeit. Es vergehen in der regel mehrere Sekunden bis mutt einsatzfähig ist.

Vor kurzem unterhielt ich mich mit Jörg Sommer darüber. Er hat eine Lösung mit zsh-Mitteln gebastelt. Diese ist zudem noch wesentlich schneller als die obige Variante:


#!/bin/zsh

hook_name=send-hook
blacklist_file=$HOME/Mail/crypt_blacklist
output_file=$HOME/Mail/crypt_hook_list

setopt extendedglob

gpg_dump=( ${(f)“$(gpg --list-keys --with-colons)”} )

# filter out lines without @
people=( ${(f)"$(for line in ${(M)gpg_dump:#(pub|uid):*@*}; do 
  print ${“${(@s.:.)line}”[10]}; done)"} )

typeset -a -U addresses
# possible bad lines:
# • email@example.com  -- only an address
# • name (<…>) 
addresses=( ${${people%>}##*<} )

[[ -r $blacklist_file ]] &&
  addresses=( ${addresses:#${(j:|:)~${${(f)"$(<$blacklist_file)"}:#\#*}}} )

print -l "$hook_name\t~A\tunset crypt_autoencrypt" \
  "$hook_name\t'~t \""${(j:|:)addresses//./\\\\.}"\"'\tset crypt_autoencrypt" \
  > $output_file

Was macht das Skript? Anfangs werden zunächst ein paar Variablen festgelegt und das erweiterte Globbing der zsh eingeschalten. In der Variable gpg_dump wird alsdann die Ausgabe von gpg --list-keys --with-colons gespeichert. Nun folgt ein wenig zsh-Magic. ;-) Die Anweisung hinter people entspricht in etwa der Shellzeile awk -F: ‘/^(pub|uid)/ { print $10 }’ gpg_dump, d.h. dort liegen dann alle E-Mail-Adressen, die auf den Schlüsseln angegeben waren. Schließlich wird für alle Adressen auf der Blackliste ein enstprechender Eintrag erzeugt und die Konfiguration in die Variable output_file geschrieben.Die Adressen in der Blackliste werden entfernt. Was übrig bleibt, schreibt das Skript in Datei, deren Name in output_file gespeichert ist. Dabei muss man beachten, dass mutt nicht unendlich viele Einträge akzeptiert. Es scheint eine Begrenzung irgendwo bei 200 Einträgen zu geben.

Das ist aus meiner Sicht eine gute Alternative zu Martins Skript. Solltet ihr Anmerkungen, Fragen, Kommentare haben, schreibt mir es unten rein oder schreibt direkt eine E-Mail an Jörg.

Update: Eine Zeile im Beitrag war ungenau formuliert. Nach einem Hinweis von Jörg habe ich das verbessert.

Das deutsche zsh-Buch ist da

Cover des zsh-Buches

Beim Schlendern durch eine Bücherei fiel mir gestern, das quasi druckfrische Buch “zsh -- Die magische Shell” auf. Seit einiger Zeit schrieben Julius Plenz und Sven Guckes daran und seit etwa einer Woche ist es im Handel erhältlich.

Im Buch geht es natürlich um die beste Shell der Welt, die zsh. Auf sechs Kapiteln in insgesamt 200 Seiten wird (hoffentlich) alles Wissenswerte gesagt. Hoffentlich deswegen, weil ich das Buch noch nicht komplett gelesen habe. Sobald ich durch bin, werde ich sicher eine Rezension dazu schreiben.

In der Einleitung finden sich kurze Hinweise zur Installation, Konfiguration und zum Prompt. Das zweite Kapitel beschäftigt sich dann mit dem effizienten Arbeiten. Es werden Aliase, Shell-Funktionen und Expansionen erklärt. Der Name des dritten Kapitels “Dateien, Ausgaben und Programmaufrufe” ist selbsterklärend. Kapitel 4 erklärt die interaktive Verwendung und Kapitel 5 das Skripting. Das letzte Kapitel des Buches beschreibt, wie Completions und Widgets selbst geschrieben werden können.

Ich bin sehr gespannt und freue mich, das Buch zu lesen. :-)

Tip #13: Dateien mit gleichen Namensbestandteilen löschen

Ich habe in einem Verzeichnis verschiedene Dateien:

jens@tacop:~/ > ls
abc.bar+bar abc.bar+foo abc.foo+bar abc.foo+baz abc.foo+foo

Nun möchte ich alle Dateien löschen, die vor und nach dem + das gleiche Wort haben, in dem Beispiel also abc.bar+bar und abc.foo+foo. Ich hatte die Hoffnung, dass das die zsh von Haus aus können könnte. Auf der Mailingliste zsh-users erhielt ich die erlösende Antwort:

rm *(e:’[[ $REPLY = abc.(#b)(???)+(???) ]] && [[ $match[1] = $match[2] ]]’:)

Tip #11: 7 im Pfad ersetzen

Wer kennt nicht das Problem, wenn man ein deutsches Tastaturlayout nutzt. Da gibt man den Pfad /usr/share7foo ein und, schwupps, schon hat sich eine 7 in die Angabe verirrt. Es wäre schön, wenn die Shell diese 7 zu einem Slash korrigieren würde. Auf der Mailingliste zsh-users wurde dazu folgende Lösung präsentiert:

function _7slash {                                                              
   local noseven=${words[CURRENT]//7/\/}                                        
   if [[ $words[CURRENT] != $noseven ]]                                         
   then                                                                         
     compadd -U -X ‘Correct 7 to /’ -f $noseven                                 
   fi                                                                           
}

Das Ganze wird mit zur Completion hinzugefügt und kann sofort genutzt werden. Die Funktion ersetzt dann jede 7 zu einem Slash. Eventuell wäre es sinnvoll, da noch etwas mehr Logik reinzustecken und so offensichtliche Fehlersetzungen auszuschließen.

über die zsh chatten

Wer von euch die beste Shell der Welt einsetzt und Fragen bzw. Kommentare hierzu hat, kann diese im IRC austauschen. Das gibt es doch schon lange, werden einige sagen. Die Neuerung ist der deutschsprachige Kanal #zsh.de auf irc.freenode.net. Also wer schon sich zur zsh in deutscher Sprache austauschen will, ist dort herzlich willkommen.

Tip #10: Alle SVN-Wurzelverzeichnisse anzeigen

Ich habe in meinem $HOME-Verzeichnis relativ verstreut diverse SVN-Verzeichnisse liegen. Das ist Software, die ich als SVN-Version nutze oder Vorlesungsmitschriften und z.T. auch Einstellungen (also Verzeichnisse mit einem Punkt am Anfang). Mein Ziel war ein Skript, was alle diese Verzeichnisse findet und dann dort ein svn update macht. Der letzte Punkt ist eher trivial. Als schwierig erwies sich das Finden der entsprechenden Verzeichnisse.

Meine erste Idee war, das Programm find zu nutzen. Mit der Zeile find $HOME -type d -name .svn erhalte ich alle Verzeichnisse, die .svn im Namen tragen. Im speziellen aber auch alle SVN-Unterverzeichnisse, die das Skript dann nicht benötigt. find hat ja noch die Option -maxdepth. Aber in diesem Falle bringt die mich nicht weiter. Nach einigem Überlegen kam ich dann dazu, die Ergebnisse an eine wilde Mischung aus sed und grep zu verfüttern. Irgendwie war das Ganze aber immer noch unbefriedigend und ich hätte lieber eine Shelllösung gehabt. Glücklicherweise war Stammtisch der LUG und ich diskutierte dort das Problem.

Nach einigem Hin und Her kamen wir dann auf die folgende zsh-Lösung:

ls_svn_dir() {
  if [ -d “$1/.svn” ]; then
    echo “$1”
  else
    for i in $1/{,.[!.]}*(/N); do
      ls_svn_dir “$i”
    done
  fi
}

ls_svn_dir “$1”

Das ist eine rekursiv definierte Shellfunktion. Diese schaut, ob das aktuelle Verzeichnis ein Unterverzeichnis .svn enthält. Falls ja, wird dieses ausgegeben. Andernfalls springt die Funktion in die for-Schleife. Das Konstrukt $1/{,.[!.]}*(/N) expandiert alle Unterverzeichnisse des in $1 stehenden (Dafür sorgt der ‘/’.) und gibt keinen Fehler aus, falls es keine Unterverzeichnisse gibt (Dafür sorgt das ‘N’.). Auf die Ergebnisse wird dann die Funktion rekursiv wieder aufgerufen.

Alles in allem ist das die Lösung, die ich mir vorgestellt habe. :-) Falls jemandem der mitlesenden zsh-Nutzer eine Verbesserung einfällt, bin ich für Vorschläge gern zu haben.

cronjob