Ich möchte die Aufteilung vieler Verzeichnisse in Unterverzeichnisse parallelisieren parallel
oder ein anderes Tool oder eine andere Methode verwenden.
Ich habe z. B. 1 000 000 Verzeichnisse mit Inhalt, aber das ist zu viel für ein Verzeichnis, also möchte ich 10 Verzeichnisse im Hauptverzeichnis erstellen und in jedes davon 100 000 Originalverzeichnisse verschieben. Ich möchte auch die Sortierung nach Datum verwenden. Ich habe bereits gefragtähnliche Frage hier, aber das ist kein Duplikat, weil ich neue Befehle ausprobiert, neue Ergebnisse erhalten und die Frage jetzt neu formuliert habe.
Also, das habe ich schon probiert
ls -tr|parallel -n100000 mkdir "dir_{#}"\;mv {} "dir_{#}"
und das
ls -tr | parallel -j10 -n100000 --no-notice -k 'mkdir -p dir_{#}; mv {} -t dir_{#}'
Befehle, aber es verschiebt nur ~10.000 in ein Unterverzeichnis (manchmal ~6.200, manchmal ~12.500) und erstellt zu viele Unterverzeichnisse – manchmal 10-mal mehr als ich brauche.
Ich habe auch versucht, dies zu verwenden:
ls -dtr * | parallel -j10 -n100000 --no-notice -k 'mkdir -p dir_{#}; mv {} -t dir_{#}'
aber es gab bash: /bin/ls: Argument list too long
.
Natürlich brauche ich nicht genau 100 000 Verzeichnisse in jedem Unterverzeichnis, es können 101 000 oder 98 500 Verzeichnisse sein, es sollte eine Zahl im Bereich von 100 000 sein
Wie kann ich diese Aufgabe parallel oder mithilfe von ausführen parallel
?
Antwort1
Das Problem besteht darin, dass es eine Obergrenze für die Anzahl der Bytes gibt, die eine Befehlszeile nach der Shell-Erweiterung aufnehmen kann. Diese Grenze hängt von der Systemgrenze ab.
getconf ARG_MAX
Dadurch variiert die Anzahl der Argumente mv {}
je nach Länge des Eingabedateinamens, wenn Sie das maximale Limit erreichen.
Eine Lösung, um diese Beschränkung zu umgehen, ohne die parallele Verarbeitung aufzugeben, besteht darin, die Aufgabe in zwei Phasen aufzuteilen.
ls -tr | parallel -N 100000 --pipe -k "mkdir dir_{#}; parallel -X mv -t dir_{#}"
Erläuterung
Der erste Schritt verwendet die Möglichkeit
--pipe
, die Standardeingabe in eine bestimmte Anzahl vonkleinere Standardeinstellungen, die jeweils n Zeilen enthalten, wie durch die Option angegeben-N
. Sie können den Effekt anhand dieses Beispiels beobachtenseq 1000000 | parallel -N 100000 --pipe wc -l
was eine genaue Aufteilung bei der 100000-Marke ergibt
100000 100000 100000 ...
Auf der zweiten Stufe nehmen die inneren Parallelen diekleinere Standardeinstellungenals neue Standardeingabe für die Ausführung ihrer Jobs,
-X
fügt die Option so viele Argumente ein, wie die Befehlszeilenlänge zulässtmkdir dir_{#}; parallel -X mv -t dir_{#}
Antwort2
Dieses Problem betrifft schwere IO. Ich bezweifle, dass das parallel
in dieser Situation wirklich nützlich ist.
Auf jeden Fall schlage ich vor, dass Sie einen „traditionellen“ Ansatz in Betracht ziehen:
mkdir dir_{1..10}
ls -tr | nl | \
awk '$2 !~ /^dir_/ {i=1+int($1/100000); print $2 | "xargs mv -t dir_"i}'
Wo
ls -tr | nl
sortiert die Verzeichnisse nach Datum und fügt eine zusätzliche Verzeichnisnummer hinzu$2 !~ /^dir_/
wird verwendet, um die gerade erstellten Ordner zu überspringen.i=1+int($1/100000)
berechnet die Nummer des Ordners anhand der Verzeichnisnummerprint $2 | "xargs mv -t dir_"i
bewegt sich ohne Prozessvermehrung
Vergleicht wenn möglich auch die jeweiligen Zeiten: time ....
(und teilt die Ergebnisse mit uns ☺)