Ich wollte nur [...] und dann ist das Universum explodiert.

Projects
Books
Archive
About









    Permalink
  1. statistical | It’s about internal functions.

    Als ich statistical auf GitHub hochgepushed habe, fing ich an mir Gedanken über die Leistungsfähigkeit des Scripts zu machen. Ich meine es verhielt sich in Anbetracht der Daten (in meinen Augen) wunderbar. Die Key Länge wird bis zu 4 Tab-Längen mit skaliert, genauso wie die Values, in Form der Bars. Aber wie verhält sich es mit größeren Datenmengen?

    Diesbezüglich wollte ich eine kleine For-Schleife benutzen um mehrere zufällige Werte zu generieren und in statistical zu pipen.

    time for x in $(seq 1 6000); do echo "$x:$RANDOM" ; done | statistical > /dev/null

    Das Ergebnis war mit 6000 Datensätzen und guten 7 Minuten relativ ernüchternd. Vor kurzem hat mich dann auch noch Vain via GitHub auf die Geschwindigkeit von statistical hingewiesen. In seinem Fork, hat er alle extern spawnenden Befehle gegen Bash interne Funktionen ausgetauscht. Siehe da:

    real 0m7.788s
    user 0m7.610s
    sys 0m0.250s

    Wahnsinn oder? Durch den Austausch von awk und grep durch interne Bash Funktionen wird das ganze ernsthaft 23x mal schneller. Vielen Dank an Vain an dieser Stelle!


  2. Permalink
  3. statistical | Statistiken visualisieren im Terminal

    Mir erschien es einen kurzen Moment lang für sinnvoll ein kleines Shell Tool zu haben, welches mir aus einer Liste von Key:Value Paaren eine Balkenstatistik baut und visualisiert. Wie in etwa $ statistical john:12 alice:5 linus:7 bob:1. Mir gefiel die Idee einfach alles mögliche in meinem Terminal ansehen zu können.

    Relativ schnell stieß ich aber an eine Grenze. Diese hieß “Windowsize”. Ich konnte nicht ohne bedenken eine Schleife die die Value Werte zählt bauen, die dementsprechend viele Zeichen anhängt. Denn bei Zahlen >10000 wird das ziemlich unlesbar :)

     while [ $COUNTER -lt $VALUE ]; do
            ((COUNTER++))
            echo -n "$OUTPUTCHAR"
            if [ $COUNTER -ge $VALUE ]; then
                echo
            fi
        done

    Ich brauchte ein Schema, welches alle Werte einließt und eine skalierbare Basis für alle Werte schafft. Ich entschied mich für eine simple Lösung.

    while [ ${FACTORCOUNT} -lt $(( ${#MAXVALUE} - 2 )) ]; do
    FACTOR="${FACTOR}0"
        ((FACTORCOUNT++))
    done
    

    Letztenendes kam dann folgendes Verhalten bei meinem Key:Value Statistik Script raus. Ich mags.

    # Beispiel
    $ statistical john:433 alice:49 linus:12 bob:231
    john    |###########################################
    alice   |####
    linus   |#
    bob     |#######################

    Damit lassen sich sogar teilweise sinnvolle Sachen produzieren. Zum Beispiel die Anzahl der Commits innerhalb eines Git-Repositories. Ich habe hier als Beispiel mal bash-it aufgeführt:

    for a in $(git shortlog -sn --all | cut -f2 | cut -f1 -d' '); do echo -n "$a:" ; git log $LOGOPTS --all --numstat --format="%n" --author=$a | cut -f3 | sort -iu | wc -l; done  | statistical
    Mark          |##################
    Robert        |#########################################################################
    Florian       |##############
    Jesus         |######
    John          |##############
    Rich          |########
    Piotr         |###
    Travis        |####
    Fedyashev     |##
    zerobearing2  |####
    Andy          |###
    Daniel        |####
    Jeff          |##
    Karl          |##
    Robert        |#########################################################################
    Sirupsen      |##
    

    Sollte jemand Interesse daran hegen, das Skript auch mal auszuprobieren es befindet sich wie immer auf Github: http://github.com/noqqe/statistical


  4. Permalink
  5. Bash | Lesen von /dev/stdin

    Gestern hat mich eine Idee für ein Skript beschäftigt. Im Detail wollte ich die Syntax:

    $ cat any_file.txt | script.sh

    abbilden. Lesen von File Descriptor 0. Also Standard-Input. Mich beschäftigte das Thema aber länger, als ich es erwartet hatte. Auf Sinn und Unsinn des Skripts möchte zumindest in diesem Blogpost nicht weiter eingehen ;)

    Versuche

    Nach kurzem bemühen einer Suchmaschine fand ich heraus, dass /dev/stdin das magische Schlüsselwort der Sache ist. Wie also von Standard Input lesen?

    cat /dev/stdin
    cat /dev/stdin > /tmp/foobar

    War in etwa mein erster Ansatz. Mich wunderte extrem, dass der übergebene Inhalt zwar ausgegeben wird, aber nicht in dem File steht. Erkenntnis daraus: File Descriptor 0 lässt sich anscheinend nur einmal auslesen. Zweiter Versuch:

    INPUT=$(cat /dev/stdin)

    Schliesslich wollte ich den Input auch im Script weiter verarbeiten. Erwies sich aber auch als ungünstig, da Zeilenumbrüche in Variablen irgendwie verschluckt werden.

    Lösung

    Anstatt hier weiterhin mit erfolglosen Lösungsansätzen herum zu schmeissen:
    cat < /dev/stdin >> /tmp/foobar

    Sieht unlogisch aus, funktioniert aber besser als alle Anderen.

    /dev/stdin und read

    Ich habe es nicht geschafft, nach dem einlesen von /dev/stdin eine bedienbare

    read irgendeinevariable

    Operation durchzuführen. Alle Eingaben werden automatisch mit dem Inhalt von /dev/stdin gefüllt. Ich konnte dafür leider noch keine Lösung finden.


  6. Permalink
  7. Bash | minimal-bash-debug

    Bei Bash Scripten gibt es ja genug Möglichkeiten zu debuggen. Jeder der Bash Scripte schreibt, hat da so seine eigenen Vorlieben. Nachdem ich etwas geforscht hatte fand ich diverse Methoden a la:

    #!/bin/bash
    _DEBUG=true
    if [ "$_DEBUG" == "true" ]; then echo "some debug informations" ; fi

    Auch schön fand ich den eingebauten Debugmodus der Shell:

    $ sh -x script.sh

    Aber auch sehr umfangreiche Tools wie log4sh sind vorhanden. Ganz zu Schweigen von wahllosen “echo’s” die über das ganze Skript verteilt sind. Irgendwie gefiel mir aber keine der Möglichkeiten so wirklich. Der Code wird unlesbar, die Ausgabe ist zu kryptisch oder der Lernaufwand ist jenseits von Gut und Böse. Deshalb habe ich mich hingesetzt und überlegt, wie ich eine Debugging-Engine gerne hätte. Wie müsste sowas aussehen, damit ich es verwenden würde?

    • Code sollte nicht verunstaltet werden.
    • Debug Informationen sollten gut leserlich ausgegeben werden.
    • Debug Nachrichten sollten sich leicht zu erzeugen sein.
    • Sollte sehr einfach abschaltbar und skalierbar sein.
    • Minimaler Umfang des Gesamtsystems

    Nunja, im typischen Sonntag Nachmittag Größenwahn hab ich mich bemüht meine Anforderungen an den Bash Debugger umzusetzen. Ob es mir gelungen ist lasse ich jetzt mal dahingestellt, denn das ist mit Sicherheit Ansichtssache. Aber das aus dem Bedarf heraus entstandene minimal-bash-debug hat mich dann doch einigermaßen zufrieden gestellt.

    Download

    
    $ cd path/to/your/bashscript
    $ wget http://github.com/noqqe/minimal-bash-debug/raw/master/.minimal-bash-debug
    $ chmod +x .minimal-bash-debug


    Implementation

    Das runtergeladene (wirklich sehr schmale) Script dient jetzt als Auswerter für die Debug Informationen. In das Bash Script, welches es zu debuggen gilt, muss nun folgende Funktion eingefügt werden. Mein Ziel Dabei war es den Snippet der Implementierung so klein wie nur irgendwie möglich zu halten, um das Skript nicht zu verunstalten.

    
    debug() {
      debug=2 # set debug level 0|1|2|3
      if [ -x .minimal-bash-debug ]; then
      ./.minimal-bash-debug $debug $1 $2 "$3"
      fi
    }


    Usage

    Die Implementation der Funktion debug() in das eigene Skript hat mehrere Vorteile. Aber zuerst zur Benutzung.

    debug 2 syslog "Variable VAR is $VAR"
    debug 3 echo "Variable FOO is $FOO"

    Das ganze ist simpel.

    • debug aufrufen (debug)
    • debug level bestimmen (2)
    • debug mode auswählen (echo|syslog)
    • debug message übergeben (Variable FOO is $FOO)

    Das war auch schon der ganze Zauber. Das schöne daran ist, ist das .minimal-bash-debug Script einmal nicht mehr vorhanden/nicht ausführbar oder das debug level einfach auf 0 gesetzt, verfallen alle debug Zeilen in sofortiges Stillschweigen.

    Der kurze Auszug der Erklärung ist natürlich relativ wenig. Deswegen gibt es auf Github http://github.com/noqqe/minimal-bash-debug/ ein Beispiel der Benutzung und ein README.

    example.sh: http://github.com/noqqe/minimal-bash-debug/raw/master/example.sh


  8. Permalink
  9. Bash | Futurama Zitate aus slashdot.org HTTP-Header auslesen

    Bin heute morgen über ein Easter-Egg von Slashdot.org gestolpert. HTTP-Header:

    $ curl -Is slashdot.org
    HTTP/1.1 200 OK
    Server: Apache/1.3.41 (Unix) mod_perl/1.31-rc4
    SLASH_LOG_DATA: shtml
    X-Powered-By: Slash 2.005001
    X-Fry: You'll barely regret this.
    X-XRDS-Location: http://slashdot.org/slashdot.xrds
    Cache-Control: no-cache
    [...]

    Bei so ziemlich jeder Anfrage steht an der Stelle ein neues Zitat. Da ich sowieso total auf Futurama stehe, dachte ich mir ich baue die Zitate als Welcome-Message in meine Rechner ein:

    $ curl -Is slashdot.org | sed -n '5p' | sed 's/^X-//'
    Bender: OK, but I don't want anyone thinking we're robosexuals.
    $ curl -Is slashdot.org | sed -n '5p' | sed 's/^X-//'
    Fry: I can burp the alphabet. A, B, D ... no, wait ...

    Wenn ich aber bei allen meinen Rechnern die Zeile einbinde, hat das irgendwie ein bisschen was von DOS-Attacke. Muss ja nicht sein. Mit einem Einzeiler hab ich mir die Quotes erstmal alle besorgt:

    target="/path/to/file/018" ; while true ; do quote="$(curl -Is slashdot.org |sed -n '5p' |sed 's/^X-//')" ; if [ $(grep "$quote" $target |wc -l) -lt 1 ]; then echo $quote >> $target ; echo $quote ; sleep 1 ; fi ; done

    Hier gibt’s alle Quotes die der Einzeiler bis jetzt gesammelt hat: http://zwetschge.org/paste/018

    Futurama Quotes beim Login unter Ubuntu:

    $ wget http://zwetschge.org/paste/018 -O ~/.futurama
    $ vi ~/.bashrc
    quotes="$HOME/.futurama"
    if [[ $- == *i* ]]; then
    echo " "
    rnd=$((RANDOM % $(cat $quotes | wc -l)+3)) ; sed -n "${rnd}p" $quotes
    fi

    Einloggen oder Shell starten sieht dann wie folgt aus:

    $ ssh user@host
    user@host password:
    Linux host 2.6.32-22-generic #33-Ubuntu SMP Wed Apr 28 13:27:30 UTC 2010 i686 GNU/Linux
    Ubuntu 10.04 LTS
    [...]
    You have new mail.
    Bender: You can't count on God for jack! He pretty much told me so himself.
    user@host:~$


  10. Permalink
  11. Bash | NerdTool Config for MacOSX

    GeekTool und NerdTool für MacOSX sind schöne Programme, welche Ausgaben von Bash-Scripten auf den Desktop ausgeben und ständig aktualiseren. Kein Geheimnis und nichts Neues.
    Das Netz ist voll von schönen Spielereien für diese Tools. Hier mein Setup. (Benutze Nerdtool, Script ist aber unabhängig von der Software)

    Bash-Script: http://gist.github.com/525385

    ESC=$(printf "\e")
    echo "$ESC[34;47mDATE$ESC[0m"
    date
    echo ""
    echo "$ESC[34;47mUPTIME$ESC[0m"
    uptime
    echo ""
    echo "$ESC[34;47mSTATUS$ESC[0m"
    top -l1 -u -o cpu -S | head -n 12
    echo ""
    echo "$ESC[34;47mEstablished$ESC[0m"
    lsof -i -n | grep -i established | awk '{print $1" "$8" "$9 }' | head -n 18
    echo ""
    echo "$ESC[34;47mListen$ESC[0m"
    lsof -i -n | grep -i listen | awk '{print $1" "$8" "$9 }' | head -n 18 

    Besonderheit hierbei: Der Escape-Character muss so _zwingend_ wie beschrieben eingesetzt werden. Normale Ausgabe wird nicht entsprechend wahrgenommen. Er ist nötig um die Farbtöne innerhalb des Scripts zu managen ;)


  12. Permalink
  13. Bash | mailrequest

    Mal wieder was aus der “Faule Sysadmins” und “wie mache ich mir _noch_ weniger arbeit”-Sparte. Desöfteren rufen Kunden an die Probleme mit ihrem Mailkonto haben. Meistens drehen sich die Probleme um die selben Themen. Angeblich nicht versandte Mails, Login-Probleme oder um Postfachgrössen, die zu klein, zu voll oder gross sind.

    Where's my mail?

    Die Prozedur ist immer die gleiche. Logfiles untersuchen. Quota ausfindig machen. Mail nachverfolgen. Je nach User individueller Mailserver. Für die grobe Arbeit, hab ich mir jetzt ein kleines Skript geschrieben, mit welchem ich (easy-usage-like ;D) mir ca 5-6 Befehle spare. Ich nannte es mailrequest. Die Kreativität hat mich nämlich einfach überrannt -_-

    Das ganze läuft jetzt wie folgt ab.

    mailrequest -s stichwort
    #Nach Queue-id, Absender, Empfaenger im aktuellen Logfile suchen.

    mailrequest -r stichwort
    #Für alle Logfiles am Mailserver

    mailrequest -q user@foobar.de
    #Postfachgroesse ermitteln

    Bis dahin hat der Plan ganz gut geklappt. Nur die Auswahl spezieller Mailserver war mir noch nicht schön genug geregelt. Mailserver jedesmal per Parameter mit übergeben müssen? Fand ich zu doof. Aber Hard-Coded im Source ist fast noch ungünstiger gewesen. Den Mittelweg hat mir die Bash ermöglicht.

    $host=$3
    $defaulthost=mail.domain.de
    ${host:-$defaulthost}

    Klartext: Wenn kein 3. Parameter definiert (oder leer) ist, wird automatisch der $defaulthost gewählt. Sollte der Mailserver nun vom Standard abweichen, kann ich ihn mitgeben. Falls nicht, kann ich mir den 3. Parameter des Aufrufs sparen.

    mailrequest -s spam@zwetschge.org mail.zwetschge.org

    Das ganze Script zum begutachten, Kritik äußern, anflamen, besserwissen: http://zwetschge.org/paste/013

    Um es wie der Typ aus der Congstar-Werbung zu sagen: “I like”.


  14. Permalink
  15. Web | Paste-Service via CommandLine (Sprunge.us)

    Sprunge.us ist ein Paste-Service den ich heute von Chris gezeigt bekommen habe. Sprunge ist aber außerdem noch _awesome_, weil er ohne Registrierung oder Umstände alles annimmt was man ihm via curl -F übergibt. Von den Entwicklern ist das wie folgt vorgesehen:

    <command> | curl -F 'sprunge=<-' http://sprunge.us
    INFO: Code: gJIJ
    INFO: URL: http://sprunge.us/gJIJ

    Und man kann unter der ausgespuckten URL den SourceCode begutachten. Den curl-Aufruf finde ich persöhnlich ziemlich lang und nicht wirklich eingängig. Das fanden anscheinend auch die Entwickler von “sprang“. Usage ungefähr so:

    cat /usr/local/scripts/script.sh | sprang
    INFO: Code: gJIJ
    INFO: URL: http://sprunge.us/gJIJ

    sprang ist ein Python-Script das mit dem sprunge.us Pastebin-Dienst interagieren kann. Man kann ihm zum Bleistift auch mit sprang -f ein Fileübergeben, mit -L Logfiles definieren oder ähnliches bewerkstelligen (genaueres mit sprang –help). Durch die Installation des python-setuptools bzw dem Kommando

    aptitude install python-setuptools; easy_install sprang

    wird der Helfer für den Dienst nutzbar. Ich muss ehrlich gestehen ich bin kein Fan von Fremdpaketsystemen. Aber diesbezüglich muss es eben sein. Alternative ist natürlich ein Bash-alias

    alias sprang="curl -F 'sprunge=<-' http://sprunge.us"

    Wobei somit die Restfunktionalität des sprang-scripts verloren geht. Besonders schön ist auch das Syntax Highlightning. Je nach Eingespeisten Source kann man der URL beispielsweise ein ?bash oder ?py mitgeben

    http://sprunge.us/gJIJ?bash

    http://sprunge.us/gJIJ?py

    und erhält schön bunt und leserlich ge-Highlightete Versionen des gesendeten.


  16. Permalink
  17. Mail | Postfix-Aliases mit MySQL-Backend erstellen

    Ich registrierte mich vor kurzem wiedermal bei einem etwas zwielichtigem Portal. Keine begründete Behauptung, es schien mir aber trotz allem so vorzukommen. Wie üblich loggte ich mich in meinen PHPMyAdmin ein und erstellte (um SpamEmails vorzubeugen) mithilfe meines MySQL-Backends von Postfix einen Alias. In einer Tabelle gesammelt liegen sämtliche aliase und deren Empfänger-Postfach.

    address | goto
    ubuntu@zwetschge.org | mail@zwetschge.org
    spam2@zwetschge.org | mail@zwetschge.org
    spam3@zwetschge.org | mail@zwetschge.org
    spam4@zwetschge.org | mail@zwetschge.org

    Es mag jetzt mit Sicherheit User geben die MySQL mit Postfix für unnötig halten, da die Steuerung über ConfigFiles ausreicht. Auf kurz oder lang gefällt mir die MySQL einfach besser. Einfach zuhandhaben. Flexibel. Schön. Das ständige eingelogge in HTpasswd, phpmyadmin-login und herumgeklicke war mir grad nur etwas zu blöd. Ich wollte ein kleines Skript basteln das mir das adden von Aliasen per CLI ermöglicht. In etwa so:

    aliasadd <alias> <recepient>

    Via echo lässt sich mysql (nach Authentifizierung) einen Befehl übergeben:

    echo "use maildb; insert into aliases values ('$1', '$2');" | mysql -u <user> --password=<pass>

    Damit wäre auch schon das gröbste geschafft. Zumindest das Einfügen. Ein Skript zeichnet allerdings mehr aus als nur die Aufgabe die es erledigen soll. Ein Skript muss zuverlässlich sicherstellen das die Aufgabe ausgeführt wurde und dies dem Benutzer nach Möglichkeit auch noch mitteilen.

    echo "use maildb; select * from aliases where address = '$1';" | mysql -u <user> --password=<pass>

    Die vorherige Zeile sieht eigentlich nur nach ob der eingegeben Alias wirklich in der Datenbank vorkommt. Freilich(wer findet ‘freilich’ eigentlich noch seltsam in Sätzen?) könnte ich jetzt noch nach Rückgabewerten mit $? Abfragen und ähnliche if-Vorraussetzungen einbauen. Aber für die 4-5 mal im Monat in denen ich es benutze wäre das übertrieben.

    Fertig sieht das ganze dann wie folgt aus:

    #!/bin/bash
    echo "use maildb; insert into aliases values ('$1', '$2');" | mysql -u <user> --password=<pass>
    echo "use maildb; select * from aliases where address = '$1';" | mysql -u <user> --password=<pass>

    Bildschirmfoto 2010-01-09 um 12.12.35

    nochmal als Plaintext:
    http://zwetschge.org/paste/6


  18. Permalink
  19. syncN – Marke Eigenbau

    Morgen,
    habe heute Abend versucht eine Lösung zu finden meine TiddlyWiki, von der mich CrackPod überzeugt hat, zwischen der Arbeit komfortabel hin und her zu synchronisieren. TiddlyWiki muss ich vielleicht kurz erklären. Es ist eine HTML-Datei mit implementiertem JavaScript die sich quasi dynamisch immer wieder selbst neu schreibt. Diese Datei kann man relativ leicht im Browser bearbeiten und allerhand lustige Sachen darin abspeichern. Mir hat das gut gefallen und deshalb bin ich dabei geblieben. Darin sammle ich zum Beispiel Notzien, Skript-Schnipsel meiner achsotollen Skripte :D Links, Chatlogs usw. GlobalesGedächtnis sozusagen ;) Aber gut wieder zum Problem. Bin dabei ehrlich gesagt nicht wirklich auf einen grünen Zweig gekommen und hab mir ein Skriptchen geschrieben. Ist nichts weltbewegendes. Es läd eine Datei hoch und runter wie mans gerade haben will und als tollen Zusatz gibts die Check-Funktion die ein bisschen tricky die OrdnerInformationen und das Datum der gerade am Server befindenden Datei ausgibt. Wenn man die Pfade austauscht hilfts vielleicht jemandem der hier liest auch mal.

    Download

    Gruß Flo