Ich habe einen Ordner mit mehr als einer Million Dateien, die sortiert werden müssen, aber ich kann nichts wirklich tun, weil mv
diese Meldung die ganze Zeit ausgegeben wird
-bash: /bin/mv: Argument list too long
Ich verwende diesen Befehl, um Dateien ohne Erweiterung zu verschieben:
mv -- !(*.jpg|*.png|*.bmp) targetdir/
Antworten:
xargs
ist das Werkzeug für den Job. Das oderfind
mit-exec … {} +
. Diese Tools führen einen Befehl mehrmals mit so vielen Argumenten aus, wie auf einmal übergeben werden können.Beide Methoden sind einfacher durchzuführen, wenn die Liste der variablen Argumente am Ende ist, was hier nicht der Fall ist: Das letzte Argument
mv
ist das Ziel. Bei GNU-Dienstprogrammen (z. B. unter nicht eingebettetem Linux oder Cygwin) ist die-t
Option tomv
nützlich, um das Ziel zuerst zu übergeben.Wenn die Dateinamen weder Leerzeichen noch Leerzeichen enthalten
\"'
, können Sie die Dateinamen einfach als Eingabe für angebenxargs
(derecho
Befehl ist eine integrierte Bash, daher unterliegt er nicht der Begrenzung der Befehlszeilenlänge):Sie können die
-0
Option verwenden,xargs
um eine durch Nullen getrennte Eingabe anstelle des in Anführungszeichen gesetzten Standardformats zu verwenden.Alternativ können Sie die Liste der Dateinamen mit erzeugen
find
. Verwenden Sie-type d -prune
. Da für die aufgelisteten Bilddateien keine Aktion angegeben ist, werden nur die anderen Dateien verschoben.(Dies schließt im Gegensatz zu den Shell-Platzhaltermethoden Punktdateien ein.)
Wenn Sie keine GNU-Dienstprogramme haben, können Sie eine Zwischen-Shell verwenden, um die Argumente in der richtigen Reihenfolge abzurufen. Diese Methode funktioniert auf allen POSIX-Systemen.
In zsh können Sie das
mv
eingebaute laden :oder wenn Sie es vorziehen zu lassen
mv
und andere Namen weiterhin auf die externen Befehle verweisen:oder mit ksh-style globs:
Alternativ mit GNU
mv
undzargs
:quelle
shopt -s extglob
es aktivieren. Ich hatte einen Schritt in denfind
Befehlen verpasst , ich habe sie behoben.find
Befehle, die ich (jetzt) gepostet habe, funktionieren. Sie müssen beim Kopieren und Einfügen einen Teil weggelassen haben.!
? Es ist expliziter und einfacher zu verstehen als das ungerade Nachlaufen-o
. Zum Beispiel! -name '*.jpg' -a ! -name '*.png' -a ! -name '*.bmp'
Wenn die Arbeit mit dem Linux-Kernel ausreicht, können Sie dies einfach tun
Das wird funktionieren, da der Linux-Kernel vor ungefähr 10 Jahren einen Patch enthielt, der das Argument-Limit so änderte, dass es auf der Stack-Größe basierte: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/ commit /? id = b6a2fea39318e43fee84fa7b0b90d68bed92d2ba
Update: Wenn Sie mutig sind, können Sie sagen
und Sie werden mit allen Shell-Erweiterungen in Ordnung sein, solange Sie genug RAM haben.
quelle
ulimit -s unlimited
, dass er für praktisch unbegrenzte Dateien funktioniert.ulimit -s unlimited
der eigentlichen Kommandozeile liegt das Limit bei 2 ^ 31 oder 2 GB. (MAX_ARG_STRLEN
In Kernel-Quelle.)Das Argument-Übergabe-Limit des Betriebssystems gilt nicht für Erweiterungen, die im Shell-Interpreter auftreten. Zusätzlich zur Verwendung von
xargs
oderfind
können wir also einfach eine Shell-Schleife verwenden, um die Verarbeitung in einzelnemv
Befehle aufzuteilen:Hierbei werden nur die Funktionen und Dienstprogramme der POSIX Shell Command Language verwendet. Dieser Einzeiler wird durch Einrückung klarer, wobei unnötige Semikolons entfernt werden:
quelle
mv
Prozesse erzeugt, anstatt nur der wenigen, die mit der POSIX-find
Lösung @Gilles posted benötigt werden . Mit anderen Worten, dies führt zu einer Menge unnötiger CPU-Abwanderung.case
Aussage über das Ergebnis der*
Erweiterung zum Herausfiltern mehrerer Erweiterungen dem ursprünglichen!(*.jpg|*.png|*.bmp)
Ausdruck entspricht. Diefind
Antwort ist in der Tat nicht gleichwertig; es steigt in Unterverzeichnisse ab (ich sehe kein-maxdepth
Prädikat).-name . -o -type d -prune -o
schützt vor dem Abstieg in Unterverzeichnisse.-maxdepth
ist anscheinend nicht POSIX-konform, obwohl das in meinerfind
Manpage nicht erwähnt ist .Um eine aggressivere Lösung als die zuvor angebotenen zu erhalten, rufen Sie Ihre Kernelquelle auf und bearbeiten Sie sie
include/linux/binfmts.h
Erhöhen Sie die Größe
MAX_ARG_PAGES
auf etwas größer als 32. Dies erhöht die Speicherkapazität, die der Kernel für Programmargumente zur Verfügung stellt, wodurch Sie Ihren Befehlmv
oderrm
für eine Million Dateien oder was auch immer Sie tun , angeben können . Neu kompilieren, installieren, neu starten.IN ACHT NEHMEN! Wenn Sie dies für Ihren Systemspeicher zu groß einstellen und dann einen Befehl mit vielen Argumenten ausführen, PASSIEREN SCHLECHTE DINGE! Gehen Sie dabei bei Mehrbenutzersystemen äußerst vorsichtig vor. Dies erleichtert böswilligen Benutzern den Verbrauch Ihres gesamten Arbeitsspeichers!
Wenn Sie nicht wissen, wie Sie Ihren Kernel manuell neu kompilieren und neu installieren können, tun Sie am besten einfach so, als gäbe es diese Antwort vorerst nicht.
quelle
Eine einfachere Lösung
"$origin"/!(*.jpg|*.png|*.bmp)
anstelle eines catch-Blocks:Vielen Dank an @Score_Under
Für ein mehrzeiliges Skript können Sie Folgendes tun (beachten Sie,
;
bevor dasdone
gelöscht wird):Um eine allgemeinere Lösung zu erstellen, bei der alle Dateien verschoben werden, können Sie den Einzeiler verwenden:
Was so aussieht, wenn Sie Einrückungen machen:
Dadurch werden alle Dateien im Ursprung einzeln zum Ziel verschoben. Die Anführungszeichen
$file
sind erforderlich, falls die Dateinamen Leerzeichen oder andere Sonderzeichen enthalten.Hier ist ein Beispiel für diese Methode, die perfekt funktioniert hat
quelle
!(*.jpg|*.png|*.bmp)
. Sie können dies zu Ihrer for-Schleife hinzufügen, indem Sie ein Globe einfügen,"$origin"/!(*.jpg|*.png|*.bmp)
wodurch der in Kaz 'Antwort verwendete Schalter überflüssig wird und der einfache Körper der for-Schleife erhalten bleibt.Manchmal ist es am einfachsten, ein kleines Skript zu schreiben, zB in Python:
quelle
Sie können diese Einschränkung umgehen, während Sie sie noch verwenden,
mv
wenn es Ihnen nichts ausmacht, sie ein paar Mal auszuführen.Sie können Teile gleichzeitig verschieben. Angenommen, Sie hatten eine lange Liste alphanumerischer Dateinamen.
Das funktioniert. Dann knock out noch ein großes Stück. Nach ein paar Zügen können Sie einfach wieder verwenden
mv ./subdir/* ./
quelle
Hier sind meine zwei Cent, fügen Sie dies in
.bash_profile
Verwendungszweck
quelle