Bash Verzeichnisse parallel komprimieren

Krik

Fleet Admiral
Registriert
Juni 2005
Beiträge
12.086
Moin zusammen,

ich habe regelmäßig mit vielen Verzeichnissen zu tun, von denen jeder für sich gezippt werden muss.
Die Verzeichnisse kommen in der Form [Buchstabe][mehrstelligeZahl], zB "a005". Die Archive sollen in der Form [TextLeerzeichen][mehrstelligeZahl], "Archiv 005", vorliegen.

Das habe ich bisher zusammengebaut und es funktioniert auch:
Bash:
for f in *; do # gehe alle Elemente im Verzeichnis durch
    if [ -d "$f" ]; then # wenn das Element ein Verzeichnis ist...
        zip -r "Archiv ${f:1}" "$f"; # ...dann zippe es
    fi
done

Nun habe ich es aber oft mit an die hundert Verzeichnissen bzw. Archiven zu tun, da wäre es schon nützlich, so viele Kompressionsvorgänge gleichzeitig auszuführen, wie es Sinn ergibt. Ich habe einen 8-Kerner, also wären das 8 Vorgänge gleichzeitig. Die Festplatte ist eine SSD, die kommt da allemal mit.

Hat jemand eine Idee, wie man das bewerkstelligt?

Gruß
Krik
 
warum nicht tar+ pigz und dann alle Kerne nutzen? -> tar -c --use-compress-program=pigz -f tar.file dir_to_zip

Sonst: mach das lieber in Python. Parallelisierung in Bash ist fummelig. Kann man machen, aber dann darfst du von Hand forken, Prozesse beobachten, nachstarten..
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: guzzisti, Piktogramm und Bitopium
madmax2010 schrieb:
Parallelisierung in Bash ist fummelig.
Hab hier im Forum für mein eigenes Projekt den Tipp bekommen, einen systemd-Service anzulegen und frage mich gerade, ob sowas nicht auch hier die Lösung wäre.

Dann sollte er das Skript instanzieren können.
 
; durch & ersetzen (wenn es nur wenige verzeichnisse sind) ODER "sem -j <anzahl jobs> zip ..."
 
  • Gefällt mir
Reaktionen: Krik
@madmax2010
Es muss ein Archiv pro Verzeichnis sein. Programme greifen darauf zu und die verhalten sich so, wie ich es brauche, wenn alles in einem Archiv landet.

@_anonymous0815_
Mir ist nicht klar, wie ein systemd-Dienst hier helfen soll!?



Ich habe es jetzt selber hinbekommen:
Bash:
for f in *; do # gehe alle Elemente im Verzeichnis durch
    if [ -d "$f" ]; then # wenn das Element ein Verzeichnis ist...
        zip -r "Archiv ${f:1}" "$f" & # zippe das Element, warte nicht auf Prozessende
    fi
done
wait # warte bis alle Prozesse abgeschlossen sind

Geht tatsächlich so, ohne das System durch plötzliche 100 neue Prozesse in die Knie zu zwingen. Das Zippen geht gerade schnell genug dazu. :D

Es gibt wohl noch eine Variante mit xargs. Die funktioniert nicht richtig
Bash:
for f in *; do
    if [ -d "$f" ]; then
        echo "$f"
    fi
done | xargs -P 8 -I {} zip -r "Archiv {:1}" "{}";
Er wirft alles in ein Archiv namens "Archiv {:1}.zip". Hmpf! Die Idee habe ich von hier: https://www.baeldung.com/linux/bash-for-loop-parallel

@nullPtr
Parallel schaue ich mir an, vielen Dank für den Tipp!
 
  • Gefällt mir
Reaktionen: _anonymous0815_ und madmax2010
die & variante ist das einfachste aber da darf der prozess dann nicht lange dauern bzw. nicht zu viele prozesse auf einmal geben. für eine handvoll verzeichnisse OK für hunderte tausende weniger OK

mit parallel kann man die anzahl jobs leicht kontrollieren mit sem kann man befehle direkt ausführen ohne parameter ausgabe xargs verarbeitung die alles unleserlich machnt
 
  • Gefällt mir
Reaktionen: Krik
& ist wirklich simpel, wenn Du deutlich mehr Zeit beanspruchen würdest, dann eben eventuell als Systemd.

https://www.computerbase.de/forum/t...-syntaxfehler-in-script.2188910/post-29247472

Hier wurde das in meinem Thread für mein Anwendungsfall beschrieben.

Udev startet einen in systemd hinterlegten Service, übergibt dabei das Device, systemd callt das Skript mit dem übergeben Device und übergibt es an das Skript, welches das Device dann final ansteuert. Aber alles eben als eigene Instanz, das ließe sich nach oben skalieren.
 
Also ich bin happy dass das Skript jetzt in <30s durchläuft statt >2 Minuten wie früher. Das reicht mir eigentlich.
Systemd erscheint mir in meinem Fall ein wenig wie mit Kanonen auf Spatzen zu schießen. :evillol:

Vielleicht baue ich später mal das Skript in einen Verzeichnisüberwachungs-Daemon aus, der von systemd alle paar Minuten angestoßen wird, um eventuell vorhandene Verzeichnisse zu zippen und zu kopieren. Vorher muss ich mir aber erst noch mehr anlesen, da gibt es vielleicht auch andere, bessere Wege.
 
  • Gefällt mir
Reaktionen: kieleich und _anonymous0815_
Oar was zu spät?

find . -mindepth 1 -maxdepth 1 -type d -printf '%f\n' -exec tar -c --use-compress="pigz -4" -f "{}".tar.gz {} \;

Statt pizg geht für schnellere und/oder bessere Ergebnisse auch zstd mit zstd -4 -T0

An der Stelle zeigt sich auch, wie absurd schnell aktuelle Gen4 und Gen5 NVMe SSDs sind. Ein aktueller 8Kerner schafft bei akzeptabler Kompressionsrate GB/s Kompression. Da lohnt es kaum weiter Parallelisierung zu betreiben, um mehr Parallelität zu erreichen.
 
  • Gefällt mir
Reaktionen: guzzisti und Krik
Bei den ganzen Alternativen bin ich immer daran hängen geblieben, wie ich den String in {} ändern kann. Die Archive müssen "Archiv 123" heißen, wobei 123 vom Verzeichnisnamen kommt.
Ich habe hier bisher keine Lösung gefunden.
Ein "Archiv {{}:1}" klappt nicht, wenn ich aus "a123" "Archiv 123" machen will.

Nicht vergessen, bei jeder Erwähnung des Wortes "Archiv" einen zu trinken! :lol:
 
Das Umbenennen ist vergleichsweise einfach. Rename ist mit && rename <pattern> schnell angehangen und für mich ist das dann sauberer als etwaiges Gefummel auf Strings.

Problematischer ist das eher, dass Behandeln von Kollisionen. Denn du magst a123 haben und b123 und beide würden zu einem "Archive 123". Selbst wenn es jetzt nicht so ist, lässt sich sowas in der Zukunft kaum komplett ausschließen und an der Stelle wird es haarig.
 
  • Gefällt mir
Reaktionen: Krik
Ah, keine Sorge, diese Kollisionen können nicht passieren. Die Verzeichnisse kommen nicht gemischt an.
Bisher stoße ich den Prozess noch per Hand an und schau auch so, ob alles passt.

Das mit den rename probiere ich aus, danke für den Tipp! 😘
Immer wenn ich denke, "dafür gibt es nichts," stellt man fest, dass Linux dafür mindestens 10 Alternativen bereit hält. ^^
 
Das in den technischen Bereichen eigentlich fast immer so. Die meisten Probleme hatten Andere innerhalb der letzten Dekaden bereits und im Regelfall gibt es als Folge dafür Ansätze bis Lösungen. An vielen Stellen gibt es davon abgeleitet "Best Practice" bis Normen und es ist anzuraten die eigenen Probleme nach Möglichkeit derart zu verbiegen, dass sie eher diesen Beschreibungen entsprechen, als die eigenen Probleme je spezifisch zu lösen.

Da bei dir irgendwelche Ordner, wohl automatisiert erstellt werden wäre da Imho ein sinnvoller Ansatz direkt bei dieser Automatisierung anzupacken. Dann sparst du dir auch das Gefummel mit irgendwelchen Watchdogs auf das Dateisystem.
 
  • Gefällt mir
Reaktionen: Micke
Zurück
Oben