kalsan
Anmeldungsdatum: 30. Mai 2010
Beiträge: 198
|
N'Abend, ich habe wenig Erfahrung mit Shell-Programmation und kann das folgende Programm leider nicht umsetzen. Hier ist das Skript in Pseudo-Code:
| Tue Folgendes für alle JPG-Dateien in allen Unterordnern (rekursive Vorgehensweise) im aktuellen Ordner:
{
identify -format "%[jpeg:sampling-factor]" DATEINAME.JPG
WENN DIE AUSGABE DES VORHERIGEN BEFEHLS == "1x1,1x1,1x1"
{
mogrify -sampling-factor 2x1 DATEINAME.JPG
}
}
|
Wie lautet dieser Code in korrektem Shell? Danke im Voraus und liebe Grüsse, Kalsan
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 13219
|
Ungetestet
| #!/bin/bash
shopt -s globstar
for f in **/*.{JPG,jpg}; do
identify -format '%[jpeg:sampling-factor]' "$f" | egrep -q '^1x1,1x1,1x1$' \
&& mogrify -sampling-factor 2x1 "$f"
done
|
Ciao robert
|
kalsan
(Themenstarter)
Anmeldungsdatum: 30. Mai 2010
Beiträge: 198
|
Herzlichen Dank, das Skript funktioniert! Allerdings erscheint folgende Meldung:
| identify: unable to open image `**/*.JPG': @ error/blob.c/OpenBlob/2587.
|
Ist das normal? lg, Kalsan
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 13219
|
kalsan schrieb: Herzlichen Dank, das Skript funktioniert! Allerdings erscheint folgende Meldung:
| identify: unable to open image `**/*.JPG': @ error/blob.c/OpenBlob/2587.
|
Ist das normal? lg, Kalsan
Wenn Du keine Dateien mit groß geschriebener Extension hast, dann ja. Ist unschön, ich weiß. Das könnte man nochmal umbauen mit find . Ciao robert
|
Vain
Anmeldungsdatum: 12. April 2008
Beiträge: 2510
|
rklm schrieb: Das könnte man nochmal umbauen mit find .
Oder:
$ echo **/*.[Jj][Pp][Gg]
tmp/bla.jpg tmp/bla.jpG tmp/bla.JPg tmp/bla.JPG tmp/keineahnung/foo.jpg Oder mit „shopt -s extglob “ vielleicht auch (falls man die komischen
Mischformen nicht haben will):
$ echo **/*.@(jpg|JPG)
tmp/bla.jpg tmp/bla.JPG tmp/keineahnung/foo.jpg
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 13219
|
Vain schrieb: rklm schrieb: Das könnte man nochmal umbauen mit find .
Oder:
Du wirst aber das Problem nicht los, dass alle Shell-Glob-Muster zu sich selbst expandieren, wenn sie nix finden. Es sei denn man setzt "nullglob". In meiner Erfahrung klappt rekursives Globben weit schlechter als find . Man hat beim Globben auch das Problem, dass eine Kommandozeile nur eine begrenzte Länge haben darf. Das reicht zwar für die meisten Fälle aus, aber das bedeutet auch, dass erst alle Dateien gefunden werden müssen, bevor das Kommando ausgeführt werden kann. find kann da prinzipiell anders vorgehen. Ciao robert
|
schmidti411
Anmeldungsdatum: 24. Oktober 2007
Beiträge: 152
Wohnort: Berlin
|
Warum nicht mit file den Dateitypen bestimmen. Ist doch viel genauer als immer auf die Endung zu achten. (Dateiendungen sind doch was für Windowsnutzer ☺ ) # file ./wallpapers/Turtle.jpg
./wallpapers/Turtle.jpg: JPEG image data, JFIF standard 1.01 Könnte mir sowas vorstellen:
|
for F in `find . -type f`
do
file "$F" | grep JPEG 1>/dev/null 2>&1
[ $? -eq 0 ] && identify -format '%[jpeg:sampling-factor]' "$F" | egrep -q '^1x1,1x1,1x1$' && mogrify -sampling-factor 2x1 "$F"
done
|
|
Vain
Anmeldungsdatum: 12. April 2008
Beiträge: 2510
|
rklm schrieb: Vain schrieb: rklm schrieb: Das könnte man nochmal umbauen mit find .
Oder:
[...]
Stimmt. Ich hatte gestern abend im Kopf, dass du oben in deinem Schnipsel
„nullglob “ gesetzt hast, aber das ist ja ein „globstar “. 😬 Trotzdem ist Brace Expansion nochmal was anderes als Globbing, wobei ein
„nullglob “ in diesem Fall natürlich beides erschlägt: $ echo **/*.{JPG,jpg}
**/*.JPG tmp/bla.jpg tmp/keineahnung/foo.jpg
$ echo **/*.@(JPG|jpg)
tmp/bla.jpg tmp/keineahnung/foo.jpg
$ shopt -s nullglob
$ echo **/*.{JPG,jpg}
tmp/bla.jpg tmp/keineahnung/foo.jpg Die Beschränkung von „argv[] “ gilt auch nicht für „for “-Schleifen
(laut dieser
Seite ist „ARG_MAX “ neuerdings von der Stack-Größe abhängig): $ ulimit -s 256
$ bash
$ /bin/echo **
bash: /bin/echo: Argument list too long
$ for i in **; do echo "$i"; done | wc -l
208904 Aber das ist nur Spielerei. „find “ wäre insgesamt schon die schönere
Lösung, da bin ich bei dir.
schmidti411 schrieb:
Warum nicht mit file den Dateitypen bestimmen. Ist doch viel genauer
als immer auf die Endung zu achten.
Schon. Aber es ist auch um Größenordnungen langsamer. Würde ich nur
machen, wenn ich mir nicht sicher wäre, dass die Bilder „ordentliche“
Endungen haben. Dass Dateiendungen nicht nur was für Windowsnutzer sind, sieht man an
dem Beispiel auch sehr gut. Würden wir die gar nicht verwenden, dann
müsstest du fast immer „file “ benutzen, was einfach total lahm
ist. Mit Endungen hat man aber eine schöne Vorsortierung. Die Endungen wegzulassen, ergibt nur in relativ wenig Fällen einen Sinn,
finde ich. Bei ausführbaren Dateien zum Beispiel, aber da auch nur in
einem „Sonderfall“: Heißt ein Shellskript „create-all-playlists “, dann
kann ich das immer so an der Shell schreiben und – bei Bedarf – das Ding
irgendwann als Python-Skript oder C-Programm neu implementieren und
den Namen beibehalten. Das ist ein echter Mehrwert, finde ich. Aber
sonst? Wo wäre der allgemeine Vorteil, wenn ich Bildern kein „.jpg “
mehr verpassen würde?
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 13219
|
schmidti411 schrieb: Warum nicht mit file den Dateitypen bestimmen. Ist doch viel genauer als immer auf die Endung zu achten. (Dateiendungen sind doch was für Windowsnutzer ☺ )
Dateiendungen funktionieren in der Praxis erstaunlich gut. Außerdem kann find das schneller auswerten, da die Checks auf Namen eingebaut sind und man dafür nicht die Datei teilweise lesen muss.
Könnte mir sowas vorstellen:
|
for F in `find . -type f`
do
file "$F" | grep JPEG 1>/dev/null 2>&1
[ $? -eq 0 ] && identify -format '%[jpeg:sampling-factor]' "$F" | egrep -q '^1x1,1x1,1x1$' && mogrify -sampling-factor 2x1 "$F"
done
|
Das Bestimmen der Dateien in der Art wie Du das da machst ist nicht sicher in Bezug auf Leerzeichen und andere Späße in Dateinamen. Du kannst außerdem mit "grep -q" die Ausgabe unterdrücken und gleich den Exit-Status von grep auswerten. Ich würde aber lieber file --mime-type nutzen, weil das direkt den MIME Typ ausgibt. | find . -type f -exec bash -c '
for f; do
file -b --mime-type "$f" | egrep -q "^image/jpeg$" \
&& identify -format "%[jpeg:sampling-factor]" "$f" | egrep -q "^1x1,1x1,1x1$" \
&& mogrify -sampling-factor 2x1 "$f"
done
' -- {} +
|
Ciao robert
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 13219
|
Vain schrieb: Die Beschränkung von „argv[] “ gilt auch nicht für „for “-Schleifen
Gut zu wissen! Der Nachteil bleibt allerdings, dass dann erst alle Dateien gefunden werden müssen, bevor die for -Schleife loslaufen darf (theoretisch könnte man das anders machen, aber dann würde sich die Semantik ändern, da der Schleifenrumpf z.B. auch Dateien löschen könnte, die später noch gefunden würden; dann hätte die parallelisierte Version ein anderes Verhalten). find kann im Prinzip zu beliebigen Zeiten den Prozess mit -exec starten und so viele Dateinamen übergeben, wie die Kommandozeile erlaubt oder find für richtig hält (bei "-execdir ... {} +" sind es i.d.R. alle, die in einem Verzeichnis liegen).
Aber das ist nur Spielerei. „find “ wäre insgesamt schon die schönere
Lösung, da bin ich bei dir.
☺ Das einzig unschöne ist die Integration in ein Skript, finde ich. Wenn man das so macht wie ich im letzten Posting, sieht das schnell schlecht aus. Moment, hier gibt es eine schöne Möglichkeit, die aber nur funktioniert, wenn der Schleifenrumpf in einer anderen Shell laufen darf, weil er keine Daten an den Rest des Skriptes zurück liefern muss (hier der Fall):
| find . -type f -print0 | while read -d '' f; do
file -b --mime-type "$f" | egrep -q '^image/jpeg$' \
&& identify -format '%[jpeg:sampling-factor]' "$f" | egrep -q '^1x1,1x1,1x1$' \
&& mogrify -sampling-factor 2x1 "$f"
done
|
Der Trick ist, find -print0 mit read -d '' zu kombinieren: durch den leeren String als Delimiter nimmt read das Null-Byte als Delimiter. ☺ Ciao robert
|
kalsan
(Themenstarter)
Anmeldungsdatum: 30. Mai 2010
Beiträge: 198
|
Wow, das ist ja zu einer rechten Fachsimpelei geworden 😲 Ich verstehe das Skript zwar nur ansatzweise, aber ich habe es nach viel Bastelei irgendwie geschafft, einen "echo"-Befehl reinzubauen, der die Dateinamen der modifizierten Dateien wiedergibt (das ist zur Kontrolle praktisch):
| find . -type f -print0 | while read -d '' f; do
file -b --mime-type "$f" | egrep -q '^image/jpeg$' \
&& identify -format '%[jpeg:sampling-factor]' "$f" | egrep -q '^1x1,1x1,1x1$' \
&& mogrify -sampling-factor 2x1 "$f" && echo "$f"
done
|
Mit "bash meinSkript.sh" kann ich das Skript ausführen, ohne dass es zu weiteren Fehlermeldungen kommt. Aus meiner Sicht wäre das Skript somit "betriebsbereit", aber bevor ich es auf die riesige Fotosammlung loslasse, möchte ich doch noch eine Bestätigung von euch Experten, dass das Skript keine Daten zerstören wird. Was meint ihr, ist alles in Ordnung?
|
rklm
Projektleitung
Anmeldungsdatum: 16. Oktober 2011
Beiträge: 13219
|
kalsan schrieb: Wow, das ist ja zu einer rechten Fachsimpelei geworden 😲
☺ Das machen wir gerne, weil jeder etwas dabei lernt.
Ich verstehe das Skript zwar nur ansatzweise, aber ich habe es nach viel Bastelei irgendwie geschafft, einen "echo"-Befehl reinzubauen, der die Dateinamen der modifizierten Dateien wiedergibt (das ist zur Kontrolle praktisch):
Was genau verstehst Du nicht? Das müssen wir dann natürlich noch erklären.
Mit "bash meinSkript.sh" kann ich das Skript ausführen, ohne dass es zu weiteren Fehlermeldungen kommt. Aus meiner Sicht wäre das Skript somit "betriebsbereit", aber bevor ich es auf die riesige Fotosammlung loslasse, möchte ich doch noch eine Bestätigung von euch Experten, dass das Skript keine Daten zerstören wird. Was meint ihr, ist alles in Ordnung?
Ich weiß nicht, wie mogrify seinen Exit-Code nutzt. Ggf. ist das hier sicherer, was die Ausgabe angeht:
| find . -type f -print0 | while read -d '' f; do
file -b --mime-type "$f" | egrep -q '^image/jpeg$' \
&& identify -format '%[jpeg:sampling-factor]' "$f" | egrep -q '^1x1,1x1,1x1$' \
&& { mogrify -sampling-factor 2x1 "$f"; echo "$f"; }
done
|
Das echo kommt dann immer und nicht nur, wenn mogrify 0 liefert, wie in Deiner Version. Ciao robert
|
kalsan
(Themenstarter)
Anmeldungsdatum: 30. Mai 2010
Beiträge: 198
|
rklm schrieb: Was genau verstehst Du nicht? Das müssen wir dann natürlich noch erklären.
Haha, vielen Dank, das ist nicht nötig ☺ Ich sollte sowieso schon längst mal meine Nase in ein Tutorial über Skripting stecken. Zwei, drei Tage Arbeit und ich verstehe dieses und alle anderen Skripte auch. Das echo kommt dann immer und nicht nur, wenn mogrify 0 liefert, wie in Deiner Version.
Aha, wieder was gelernt: Mit dem Strichpunkt habe ich's auch schon probiert, aber ohne Erfolg. Anscheinend fehlten die Klammern. Ciao
robert
Vielen vielen Dank für all die grossartige Hilfe! Nun kann ich mich endlich an die Datenbank wagen 👍 lg, Kalsan
|
kalsan
(Themenstarter)
Anmeldungsdatum: 30. Mai 2010
Beiträge: 198
|
Herzlichen Dank nochmals, das hat wunderbar geklappt ☺ lg, Kalsan
|