Bei Argument list too longFehlern sind drei wichtige Punkte zu beachten :
Die Länge der Befehlszeilenargumente ist durch eine ARG_MAXVariable begrenzt , die laut POSIX-Definition "... [m] maximale Länge der Argumente für die exec-Funktionen einschließlich Umgebungsdaten" (Hervorhebung hinzugefügt) ist. Das heißt, wenn die Shell ein non ausführt -built-it-Befehl, muss einen von aufrufen exec(), um den Befehlsprozess zu erzeugen, und genau hier ARG_MAXkommt es an. Außerdem spielt der Name oder der Pfad zum Befehl selbst (zum Beispiel /bin/echo) eine Rolle.
Shell-Befehle werden von der Shell ausgeführt. Dies bedeutet, dass die Shell keine exec()Funktionsfamilie verwendet und daher von ARG_MAXVariablen nicht betroffen ist.
Bestimmte Befehle, wie z. B. xargsund findkennen ARG_MAXVariablen und führen Aktionen unter dieser Grenze wiederholt aus
Aus den obigen Punkten und wie in Kusalanandas hervorragender Antwort auf verwandte Fragen gezeigt, Argument list too longkann dies auch auftreten, wenn die Umgebung groß ist. In Anbetracht der Tatsache, dass die Umgebung jedes Benutzers variieren kann und die Argumentgröße in Byte relevant ist, ist es schwierig, eine einzige Anzahl von Dateien / Argumenten zu finden.
Wie gehe ich mit solchen Fehlern um?
Das Wichtigste ist, sich nicht auf die Anzahl der Dateien zu konzentrieren, sondern darauf, ob der Befehl, den Sie verwenden möchten, eine exec()Funktionsfamilie und tangential - den Stapelspeicherplatz - umfasst.
Verwenden Sie Shell-Built-Ins
Wie bereits erwähnt, sind die Shell-Built-Ins unempfindlich gegen ARG_MAXEinschränkungen, wie z. B. forLoop, whileLoop, Built-In echound Built-In. printfAll diese sind ausreichend leistungsfähig.
for i in /path/to/dir/*; do cp "$i" /path/to/other/dir/; done
Bei verwandten Fragen zum Löschen von Dateien gab es eine Lösung als solche:
printf '%s\0' *.jpg | xargs -0 rm --
Beachten Sie, dass hierfür die integrierte Shell verwendet wird printf. Wenn wir das Externe anrufen printf, wird dies einbeziehen exec()und daher mit einer großen Anzahl von Argumenten scheitern:
$ /usr/bin/printf "%s\0" {1..7000000}> /dev/null
bash: /usr/bin/printf: Argument list too long
Bash-Arrays
Laut einer Antwort von jlliagre bashgibt es keine Einschränkungen für Arrays. Daher können auch Arrays von Dateinamen erstellt und Slices pro Schleifeniteration verwendet werden, wie in der Antwort von danjpreron gezeigt :
files=( /path/to/old_dir/*.prj )
for((I=0;I<${#files[*]};I+=1000)); do
cp -t /path/to/new_dir/ "${files[@]:I:1000}"
done
Dies hat jedoch die Einschränkung, bash-spezifisch und nicht POSIX-spezifisch zu sein.
Erhöhen Sie den Stapelplatz
Manchmal kann man die Menschen sehen , deuten darauf hin , Erhöhung der Stapelspeicher mit ulimit -s <NUM>; Unter Linux beträgt der ARG_MAX-Wert 1/4 des Stapelspeichers für jedes Programm, was bedeutet, dass durch Erhöhen des Stapelspeichers der Speicherplatz für Argumente proportional erhöht wird.
# getconf reports value in bytes, ulimit -s in kilobytes
$ getconf ARG_MAX
2097152
$ echo $(( $(getconf ARG_MAX)*4 ))
8388608
$ printf "%dK\n" $(ulimit -s) | numfmt --from=iec --to=none
8388608
# Increasing stack space results in increated ARG_MAX value
$ ulimit -s 16384
$ getconf ARG_MAX
4194304
Laut der Antwort von Franck Dernoncourt , der das Linux Journal zitiert, kann man den Linux-Kernel auch mit einem höheren Wert für maximale Speicherseiten für Argumente neu kompilieren. Dies ist jedoch mehr Arbeit als nötig und eröffnet das Potenzial für Exploits, wie im zitierten Artikel im Linux Journal angegeben.
Vermeiden Sie Muscheln
Eine andere Möglichkeit ist die Verwendung von pythonoder python3die standardmäßig mit Ubuntu kommen. Das folgende Python + Here-Doc- Beispiel wurde von mir persönlich verwendet, um ein großes Verzeichnis mit Dateien im Bereich von 40.000 Elementen zu kopieren:
$ python <<EOF
> import shutil
> import os
> for f in os.listdir('.'):
> if os.path.isfile(f):
> shutil.copy(f,'./newdir/')
> EOF
Für rekursive Durchläufe können Sie os.walk verwenden .
Siehe auch: