Verwenden Sie parallel, um viele Verzeichnisse in Unterverzeichnisse aufzuteilen oder diese Aufgabe zu parallelisieren

Verwenden Sie parallel, um viele Verzeichnisse in Unterverzeichnisse aufzuteilen oder diese Aufgabe zu parallelisieren

Ich möchte die Aufteilung vieler Verzeichnisse in Unterverzeichnisse parallelisieren paralleloder 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 beobachten

    seq 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, -Xfügt die Option so viele Argumente ein, wie die Befehlszeilenlänge zulässt

    mkdir dir_{#}; parallel -X mv -t dir_{#}
    

Antwort2

Dieses Problem betrifft schwere IO. Ich bezweifle, dass das parallelin 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 Verzeichnisnummer
  • print $2 | "xargs mv -t dir_"ibewegt sich ohne Prozessvermehrung

Vergleicht wenn möglich auch die jeweiligen Zeiten: time ....(und teilt die Ergebnisse mit uns ☺)

verwandte Informationen