Main /

Script Mehrfach

Allgemein

Knowledge Base

Virtualisierung Emulation

Technik und Wissen

Community

Privat

%center%[[http://validator.w3.org/check?uri=referer|http://www.w3.org/Icons/valid-xhtml10.png]]%%

Script Mehrfach

/ HomePage / Computer / Software / Programmierung / Massenverarbeitung

Scripte für die Massenverarbeitung

Eigentlich sind Scripte für die wiederkehrende Verarbeitung prädestiniert. Wer einmal ein Bild mit Gimp skaliert hat, weiß was das für ein Aufwand ist. Bild öffnen, Bild skalieren, Bild speichern. Das mag sich nicht kompliziert anhören, ist es eigentlich auch nicht, nur, wenn man das dann 10x machen soll wird es schnell langwierig und fehleranfällig, da immer wieder die selben Schritte vorgenommen werden sollen. Ok, für nur 10x kann man es eben noch machen, aber sobald man es irgendwann nochmal machen soll... ist es stupide Arbeit.

Voraussetzungen

Ein Script, oder ein Programm das die Arbeit erledigt. Zum Bearbeiten von Bildern per Script bietet sich ImageMagick an.

 convert <Datei> -scale 320x <Neue_Datei>

Ein Script zur Bildskalierung genau einer Datei

Es bleibt also nur die Verarbeitung des Dateinamens.

 #!/bin/bash
 # Prüfen, ob ein Parameter übergeben wurde
 if [ $# -eq 0 ]; then
     echo "Usage: $0 <Datei>"
     exit 1
 fi

 if [ ! -e "$1" ]; then
     echo "Datei existiert nicht"
     exit 1
 fi

 # Datei zerlegen in dessen eigentlichen Namen und dem Pfad dazu
 BASENAME=$(basename $1)
 DIRNAME=$(dirname $1)

 NEWNAME="img_320x_${BASENAME}"
 NEWPATH=$DIRNAME/$NEWNAME

 if [ -e "$NEWPATH" ]; then
     echo "Neue Datei existiert bereits"
     exit 1
 fi

 # hier passiert die Umwandlung
 convert $1 -scale 320x $NEWPATH

Zu speichern als resizeTo320x

Damit können wir jetzt exakt ein Bild in einem beliebigen angegebenen Pfad in 320x wandeln. Die neue Datei fängt immer mit 'img_320x_' an. Es gibt hier zusätzlich ein paar Sicherheitsabfragen, nur um mal zu zeigen wie man das machen könnte.

Script mehrfach wieder verwenden

Wir wollen die resizeTo320x jetzt aber mehrfach aufrufen.

 find . -name '*.jpg' -exec /.../resizeTo320x {} \;

Das tippt man eben so runter.

Nachteile

  • Es werden nur .jpg berücksichtigt, -iname '*.jpg' ist Case-insensitiv.
  • Es werden nur Bilder vom Type JPEG berücksichtigt
 find . -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.bmp' -o -iname '*.gif' \ 
-o -iname '*.png' -o -iname '*.tif' -o -iname '*.tiff' -exec /.../resizeTo320x {} \;

Das tippt niemand mehr.

Q: Aber wie die beiden Scripte miteinander verbinden?
A: Pipe!

Liste erstellen

Also erstellen wir ein Script, was sämtliche Bilder findet.

 find . -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.bmp' -o -iname '*.gif' \ 
-o -iname '*.png' -o -iname '*.tif' -o -iname '*.tiff'

Speichern als listpics

Damit kann man alle Bilder von Typ jpg, jpeg, bmp, gif, png, tif, tiff von der aktuellen Pfad-Position finden, die Namen werden auf der Konsole (Standard out) ausgegeben. Ggf. erweitern.

 listpics | resizeTo320x

Das funktioniert so allerdings nicht, da resizeTo320x nur mit Parametern arbeitet und nicht mit Übergaben aus dem Standard Input.

Standard Input zu Parameteraufruf wandeln

Man könnte jetzt die resizeTo320x dahingehend erweitern, das sie beides kann, mit Parametern umgehen und mit Standard Input zurecht kommt, da resizeTo320x aber nur ein Beispiel sein soll, muss eine andere Lösung her.

Warum nicht ein weiteres Script, das uns diese Arbeit abnimmt. Also alle per Standard Input ankommenden Parameter einfach in Parameter umsetzt und unser Script damit aufruft.

 #!/bin/bash

 if [ $# -eq 0 ]; then
     echo "Caller: which program should be called?"
     exit 1
 fi

 # echo "external program: $1"
 CALLER="$1"

 shift

 if [ $# -eq 0 ]; then
    # rufe übergebenes Program mit jeden Parameter der per Standard Input reinkommt
    read parameter
    while [ -n "${parameter}" ]; do
        # echo ${CALLER} $parameter
        ${CALLER} $parameter
        shift
        read parameter
    done

 else
    # übergebe alle Parameter einzeln an das übergebene Program
    while [ $# -ne 0 ]; do
        ${CALLER} $1
        shift
    done
 fi

Speichern als caller

Nun können wir auf der einen Seite Listenausgaben (fast) direkt an andere Scripte übergeben. Ohne uns in jedem Script Gedanken darüber zu machen, wie man es mehrfach anwendet.

 listpics | caller resizeTo320x

listpics findet beliebig viele Bilder und übergibt diese an den caller der für jeden Standard Input unser Programm resizeTo320x aufruft. Wir brauchten das resizeTo320x nicht mehr anpassen, um mit einem Parameter oder mit Standard Input zurechtzukommen. Der Stapelverarbeitung steht nichts mehr im Weg...

Fazit: Gibt es doch schon mittels xargs

Ok ok, gibt es schon. Das hier beschriebene Verfahren ist auch nur mal ein Beispiel, wie man es machen könnte und so etwas gibt es auch schon, wer sich mit Stapelverarbeitung auskennt, weiß dass es dafür xargs gibt.

 listpics | xargs -n 1 resizeTo320x

Der xargs Parameter -n 1 besagt, das unser Programm resizeTo320x für jeden Parameter explizit aufgerufen wird, sonst würden solange Parameter übergeben wie die Shell hergibt (bis zu 32000 Zeichen)

  • (ohne -n 1) resizeTo320x bild1 bild2 bild3 ... bildN
  • (mit -n 1) resizeTo320x bild1 ; resizeTo320x bild2 ...

Der caller soll ja auch nur mal aufzeigen, wie xargs intern funktioniert.

DNG to JPG Batch Konvertierung

Ich konvertiere alle meine Bilder von den propritären Raw Formaten der Kamarahersteller *.cr2, *.nef, etc. immer in das Adobe dng Format. So nutze ich ein einheitliches und offenes Format, um alle Bilder zu archivieren. Dennoch kommt es vor, dass man die Bilder an andere Personen weitergeben möchte. Dafür eignet sich das jpg Format deutlich besser. Um ein ganzes Verzeichnis von dng zu jpg zu konvertieren, habe ich mir folgendes batch geschrieben.

Vorraussetzung sind imagemagick und unf ufraw. Unter Ubuntu zu installieren mit:

 sudo apt-get install imagemagick ufraw
 #!/bin/bash
 for f in *.dng
 do
         BASENAME=$(basename $f .dng)
         NEWNAME=$BASENAME.jpg

         convert -quality 85% $f $NEWNAME
 done

Dateien mit gewissen Schema kopieren

 find . -iname '*schema*' -print0 | xargs -0 -I MYFILE cp MYFILE /tmp/destinationdir

Kopiert mal eben sämtliche Dateien, egal in welchem Unterverzeichnis die '*schema*' im Namen haben nach /tmp/destinationdir. Ist doch eigentlich ganz einfach.

Links

Frische Änderungen (All) | Edit SideBar Zuletzt geändert am 24.12.2011 14:03 Uhr Seite Bearbeiten | Seitenhistorie
Powered by PmWiki