Batch-Löschung kleinerer Dateien aus einer Dateigruppe über die Unix-Befehlszeile

3

Ich habe eine große Anzahl (mehr als 400) von Verzeichnissen voller Fotos. Was ich tun möchte, ist, die größeren Größen dieser Fotos zu behalten. Jedes Verzeichnis enthält 31 bis 66 Dateien.

Jedes Verzeichnis verfügt über Miniaturansichten und größere Versionen sowie eine Datei mit dem Namen example.jpg

Ich versandte die example.jpg-Datei einfach mit:

rm */example.jpg

Anfangs dachte ich, dass es einfach wäre, die Thumbnails zu löschen, aber das Problem ist, dass sie nicht einheitlich benannt sind. Das typische Muster war photo1.jpgund photo1s.jpg. Ich tat es, rm */photo*s.jpgaber es endete damit, dass einige der genannten Dateien photoXs.jpgtatsächlich größer und nicht kleiner waren. Argh.

Ich möchte also jedes Verzeichnis nach Dateigröße durchsuchen und die Miniaturansichten löschen (oder verschieben). Anfangs dachte ich, ich würde nur ls -Rjede Datei und die Größe jeder Datei extrahieren und diese unter einem Schwellenwert speichern. Das Problem? In einem Verzeichnis beträgt die Größe 1,1 MB und der Thumb 200 KB. In einem anderen ist der große 200k und der kleine 30k.

Schlimmer noch, die Dateien haben in Wirklichkeit meistens einen Namen photo1.jpg- also würde es nicht funktionieren, sie alle in denselben Ordner zu legen, nach Größe zu sortieren und in Gruppen zu löschen, ohne sie bereits umzubenennen. Wenn es möglich ist, würde ich es vorziehen, sie in ihren Ordnern zu belassen.

Ich war fast entschlossen, das alles manuell zu machen, dachte dann aber, ich würde hier fragen.

Wie würden Sie diese Aufgabe erledigen?

artlung
quelle
Gibt es eine Beziehung zwischen dem Namen eines Bildes und dem Miniaturbild oder Bildern anderer Größe?
Marnix A. van Ammers

Antworten:

1

In diesem Skript wird davon ausgegangen, dass zwischen den Gruppen der kleinsten und der größten Datei eine erhebliche Größenlücke besteht. Insbesondere, dass die kleinste der großen Dateien mindestens doppelt so groß ist wie die größte der kleinen Dateien.

Rufen Sie das Skript "imagedirstats" auf und führen Sie es in einer Schleife wie der folgenden aus:

find /path/to/main/branch -type d | while read subdir; do (cd "$subdir" && ~/bin/imagedirstats ); done

um Dateien in einzelnen Verzeichnissen im Verzeichnisbaum zu finden und zu löschen.

Hier ist das Skript:

#!/bin/bash
# from http://superuser.com/questions/135951/batch-deletion-of-smaller-files-from-group-of-files-via-unix-command-line
# by Dennis Williamson - 2010-04-29

prevn=1     # prevent division by zero
factor=4    # how close to the largest of the small files to set the threshold, 4 == one fourth of the way above
min=1000    # ignore files below this size

while read n
do
    (( ratio = n / prevn ))
    if (( ratio > 1 && n > min ))
    then
        break
    fi
    if (( n > 0 ))
    then
        prevn=$n
    fi
done < <(find . -maxdepth 1 -name "*.jpg" -printf "%s\n" | sort -n)
# for OS X, comment out the preceding line and uncomment this one:
# done < <(find . -maxdepth 1 -name "*.jpg" | stat -f "%z" | sort -n)

# the following line would be the GNU equivalent using stat(1) instead of printf
# it's included here for reference:
# done < <(find . -maxdepth 1 -name "*.jpg" | stat -c "%s" | sort -n)

(( size = (n - prevn) / factor + prevn ))

echo "Smallest of the large: $n"
echo "Largest of the small: $prevn"
echo "Ratio: $ratio"
echo "Threshold: $size"

if (( ratio < 2 ))
then
    read -p "Warning: ratio too small. Delete anyway? Only 'Yes' will proceed" reply
    if [[ $reply != "Yes" ]]
    then
        echo "Cancelled" >&2
        exit 1
    fi
fi

# uncomment the delete on the following line to actually do the deletion

find . -maxdepth 1 -name "*.jpg" -size -${size}c # -delete

Bearbeiten: Die Warnmeldung wurde verschoben, sodass zuerst nützliche Informationen angezeigt werden. Fehlende behoben fi.

Bearbeiten 2: Die beiden findBefehle wurden konsistent gemacht. Auskommentierte Variante für OS X hinzugefügt. Informationen zum Ausführen des Skripts hinzugefügt.

Dennis Williamson
quelle
Gespeichert als imagedirstats:und rannte es mit ~/bin/imagedirstats */*und das Ergebnis ist: -bash: /Users/artlung/bin/imagedirstats: Argument list too long... ~/bin/imagedirstats *find: illegal option -- p find: illegal option -- r find: illegal option -- i find: illegal option -- n find: illegal option -- t find: %s\n: No such file or directory /Users/artlung/bin/imagedirstats: line 38: syntax error: unexpected end of file
renne
Das Skript akzeptiert keine Argumente. Es kann im aktuellen Verzeichnis oder in einer Schleife ausgeführt werden, die über eine Reihe von Verzeichnissen iteriert. Sehen Sie auch, wo ich den findBefehl bearbeitet habe . Ich habe vergessen, ein -maxdepthArgument aufzunehmen.
Dennis Williamson
Was gibt find --versiondir Welche Linux Distribution (und Version)?
Dennis Williamson
Der Grund für die Einschränkungen von current-directory und maxdepth besteht darin, die von Ihnen in Ihrer Frage beschriebene Bedingung zu berücksichtigen, dass sich die Dateigrößenbereiche in verschiedenen Verzeichnissen überschneiden.
Dennis Williamson
So könnte die äußere Schleife aussehen:find /path/to/main/branch -type d | while read subdir; do (cd "$subdir" && ~/bin/imagedirstats ); done
Dennis Williamson
4

Wenn Sie einen bestimmten Ausschnitt finden, zum Beispiel, dass alle großen Bilder größer als 200 KB sind, können Sie dies tun:

find */*.jpg -size -200k -delete

Möglicherweise möchten Sie zuerst eine Sicherungskopie erstellen.

Chris S
quelle
Das ist vielversprechend. Leider gibt es keine klare Größenbeschränkung, aber dies ist ein guter Weg, um eine Mehrheit einzugrenzen. Vielen Dank!
Artlung
3

Wenn die Dateigrößen nicht konsistent sind, sind die Bildabmessungen?

Sie können identifyein mit ImageMagick geliefertes Werkzeug verwenden, um die Bildabmessungen zu erfassen. Mit einfachen Bash-Skripten können Sie die Bilder je nach Größe bearbeiten.

So erfassen Sie die Breite und Höhe eines Bildes mit identify:

identifiziere -format '% wx% h' Dateiname

Sie erhalten eine Ausgabe wie folgt:

[john @ awesome: ~] $ identification -format '% wx% h' W4.JPG
1680 x 1050

Sie können dann das cutDienstprogramm verwenden, um die Zahlen in Ihrem Skript zu erfassen:

[john @ awesome: ~] $ identity -format '% wx% h' W4.JPG | schneide -d'x '-f1
1680
[john @ awesome: ~] $ identity -format '% wx% h' W4.JPG | schneide -d'x '-f2
1050
John T
quelle
Okay, installiere imagemagick via brew (auf dem Mac) und schau es dir an. Dies ist ein Stück zum Herausziehen der Höhe. Ich denke, es gibt eine gewisse Konsistenz in den Höhen der Thumbnails - nicht in den größeren. Vielversprechend!
Artlung
Auch wenn sie nicht genau übereinstimmen, können Sie dies tun, wenn alle Miniaturansichten weniger als 200 Pixel hoch sindif [ $h -lt 200 ] ...
John T
0

Wenn Sie dies auf der Grundlage des Dateinamens tun möchten, versuchen Sie Folgendes:

find -name '*.jpg' | sed -ne 's:^\(.*\)\.jpg:\1s.jpg$:p' | xargs rm

Es findet jede .jpg-Datei, setzt ein "s" am Ende des Dateinamens (kurz vor dem ".") Und löscht es.

petersohn
quelle
1
Das OP sagte, die Dateien seien inkonsistent benannt und einige der großen Dateien hätten "s".
Dennis Williamson
Danke petersohn, aber DW hat recht. Wenn sie so benannt würden, wie eine vernünftige Person sie benennt, wäre es viel einfacher, Dateien zu löschen, die dem Muster entsprechen, und fertig.
Artlung