batch image resize/convert

  • Hi,

    Ich versuche nun schon seit Stunden ein simples Script zu schreiben...

    Ich habe einen Ordner "Bildertemp", und darin liegen zwei Ordner "Vorher" und "Nacher". Im Ordner "Bildertemp" soll nun auch noch ein kleines ausführbares Script liegen, das folgendes tun soll:

    Im Ordner "Vorher" liegen einige jpgs, und nun sollen beim Ausführen des Scripts alle jpgs per "convert -resize 35% -quality 85" verkleinert und qualitativ etwas verschlechtert werden. Ausserdem sollen die dabei erstellten neuen jpgs im Ordner "Nacher" abgelegt werden, wobei die Originale unverändert im Ordner "Vorher" bleiben sollen. Evtl. sollen die neuen jpgs ein suffix à la "resized-" erhalten.

    Angenommen man will lediglich alle jpgs eines Ordner konvertieren, ohne sie zu verschieben, kann das script so aussehen:

    Zitat

    #!/bin/sh

    find ./ -name '*.jpg' -exec convert -resize 35% -quality 85 {} {}.jpg \;

    Doch da ich sie ja verschoben haben will, und das script ausserdem im übergeordneten Ordner liegt, schrieb ich es so:

    Zitat

    #!/bin/sh

    find ./Vorher/ -name '*.jpg' -exec convert -resize 35% -quality 85 {} ../Nacher/{}.jpg \;

    Dies funktioniert allerdings nicht, weil "find -name" immer den ganzen Pfad an {} sendet, in diesem Fall also "./Vorher/*.jpg", was darin resultiert, dass der Zielpfad bei "convert" nun "../Nacher/./Vorher/*.jpg.jpg" lautet, was völliger Unsinn ist.

    Also versuchte ich es so:

    Zitat

    #!/bin/sh

    cd Vorher/
    find ./ -name '*.jpg' -exec convert -resize 35% -quality 85 {} resized-{}.jpg \;
    mv resized* ../Nacher/

    Aber auch dies schlägt fehl, weil convert auch in diesem Fall "resized-./*.jpg.jpg" verwendet. Das Problem liegt also darin, dass ich nur den Namen der Datei brauche, also *, und weder *.jpg, noch ./*.jpg.

    Wie muss ich find verwenden, um nur den Namen der Datei in {} eingesetzt zu bekommen? Oder gibt es eine andere möglichkeit, viele Bilder gleichzeitig und in einem Zug zu konvertieren? Vielleicht sogar mit Fortschrittanzeige? Evtl. ein Programm im Stil von IrfanView für Windows?

  • Bash
    #!/bin/sh
    
    
    cd ./Vorher
    for i in `ls -1 *.jpg`; do
     convert -foo -bar ./$i ../Nachher/`basename $i .jpg`-resized.jpg
    done

    Willfähriges Mitglied des Fefe-Zeitbinder-Botnets und der Open Source Tea Party.

  • Zitat von Kampi
    Bash
    #!/bin/sh
    
    
    cd ./Vorher
    for i in `ls -1 *.jpg`; do
     convert -foo -bar ./$i ../Nachher/`basename $i .jpg`-resized.jpg
    done


    Dein Konstrukt fuer die Liste der for-Schleife ist ein ziemliches Gehumpel :D, da das Ganze bei einem Zeilenumbruch in Dateinamen sowieso failed (und eigentlich vollkommen redundant ist, weil du fuer `ls` auch nur die Expanson der Shell nutzt). Basename ist in dem Fall auch hoechstens Zierde, da du nur die Dateinamen in die Liste bekommst, und keinen wie auch immer gearteten Pfad.

    Eine etwas elegantere Variante fuer triviale Faelle waere zum Beispiel:

    Bash
    #!/bin/bash
    
    
    cd ./Vorher
    for i in *.jpg; do
     convert -foo -bar ./"${i}" ../Nachher/"{i/.jpg/-resized.jpg}"
    done


    Zum (neuen) Konqueror-Problem des Threadstarters:
    Ich nutze selbst kein KDE, habe aber kuerzlich jemandem unter die Arme gegriffen, der das offenbar tut. Vielleicht kannst du damit was anfangen: http://www.ubuntuforums.org/showpost.php?p=787560&postcount=4

    Hth :)

  • Zitat von colo

    Dein Konstrukt fuer die Liste der for-Schleife ist ein ziemliches Gehumpel :D, da das Ganze bei einem Zeilenumbruch in Dateinamen sowieso failed (und eigentlich vollkommen redundant ist, weil du fuer `ls` auch nur die Expanson der Shell nutzt).

    Wer zeilenumbrueche in dateinamen hat, der hat es nicht anders verdient ;-). Dass es so wie du es geschrieben hast auch funktioniert, wuszte ich schlicht und einfach nicht. Aber in der tat ist es viel eleganter.

    Zitat von colo


    Basename ist in dem Fall auch hoechstens Zierde, da du nur die Dateinamen in die Liste bekommst, und keinen wie auch immer gearteten Pfad.

    Auch das hab ich so nicht gekannt, aber auch viel feiner. Um noch irgendwie die kurve zu bekommen sag ich mal meins ist vielleicht in irgendwelchen dubiosen shells durch die verwendung der kommandos und nicht duch das verwenden der shell-features etwas portabler.

    Willfähriges Mitglied des Fefe-Zeitbinder-Botnets und der Open Source Tea Party.

  • Falls mein Posting als harsche Kritik ruebergekommen sein sollte, tut mir das leid - so war es nicht gedacht. Man lernt eben nie aus, und oft erwischt es die Besten ganz besonders kalt ;) :D

    Noch eine kleine Wortspende zum eigentlichen Sachthema:

    Die Substitution in Variablen in der Shell durch ${VARIABLE/STRING/REPLACEMENT} kann afaik nur die bash - insofern ist diese Variante wenig(er) portabel(, als etwas, das z. B. durch sed piped). Man kriegt mit meiner Variante auch Probleme, wenn ein Dateiname (in der Bash, nicht als RegExp) gegen *.jpg?* matcht, weil dann nicht die Dateiendung modifiziert wird, sondern das erste Vorkommen von ".jpg".


    Was den "Konstruktor" der Liste betrifft im urspruenglichen Skript, will ich das mit einem Beispiel deutlicher machen:

    Das sollte die Redundanz von "for i in `ls -1 *`;" eigentlich zeigen - hier wird naemlich fuer "*" in der Subshell schon durch die Shell substituiert, und zwar mit jedem Eintrag im aktuellen Verzeichnis - das passiert durch die Shell, nicht durch ls! Man uebergibt ls also nur eine Menge von Files, die gar keine anderen als die sein koennen, die sowieso schon auf die gegebene Pattern in der Shell matchen. Der Joker * matcht in allen POSIX implementierenden Shells gleich, deswegen muss man sich also keine Sorgen machen.

    Sollte man einmal Probleme mit dem "Aufspueren" von Dateien haben, weil irgendein Idiot (oder Ungebildeter ;)) Mist im Dateinamen gedreht hat (z. B. ein \n - zwar wirklich "selber Schuld", aber kommt vor!), hilft nur noch `find` weiter. In der zugehoerigen Manpage lege ich die Lektuere der Actions "-exec" und "-print0" an's Herz.

    Ich hab kuerzlich ein (sehr schmutzig-schnelles ;)) Skript geschustert, das "boese" Zeichen quasi halbautomatisch aus Dateinamen wirft. Zu finden hier: http://gnulords.org/~colo/tmp/sanitize.sh

    Und ja, mir war grade ein bisschen fad :D

  • Zitat von colo

    Das sollte die Redundanz von "for i in `ls -1 *`;" eigentlich zeigen - hier wird naemlich fuer "*" in der Subshell schon durch die Shell substituiert, und zwar mit jedem Eintrag im aktuellen Verzeichnis - das passiert durch die Shell, nicht durch ls!


    Man sollte hier überhaupt nicht "for i in `ls -1 *`" verwenden, wie man sich leicht klarmachen kann, wenn man das mit einem Verzeichnis ausprobiert, in dem Dateien mit Leerzeichen im Dateinamen enthalten sind.

Jetzt mitmachen!

Sie haben noch kein Benutzerkonto auf unserer Seite? Registrieren Sie sich kostenlos und nehmen Sie an unserer Community teil!