Bei Argument list too long
Fehlern sind drei wichtige Punkte zu beachten :
Die Länge der Befehlszeilenargumente ist durch eine ARG_MAX
Variable 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_MAX
kommt 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_MAX
Variablen nicht betroffen ist.
Bestimmte Befehle, wie z. B. xargs
und find
kennen ARG_MAX
Variablen 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 long
kann 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_MAX
Einschränkungen, wie z. B. for
Loop, while
Loop, Built-In echo
und Built-In. printf
All 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 bash
gibt 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 python
oder python3
die 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: