“ Argumentliste zu lang ”: Wie gehe ich damit um, ohne meinen Befehl zu ändern?

Wenn ich einen Befehl wie ls */*/*/*/*.jpg ausführe, wird der Fehler

Ich weiß, warum dies passiert: Dies liegt daran, dass der Speicherplatz für Argumente für einen Befehl im Kernel begrenzt ist. Der Standardempfehlung besteht darin, den von mir verwendeten Befehl zu ändern, um zu vermeiden, dass so viel Platz für Argumente benötigt wird (z. B. find und xargs).

Was ist, wenn ich den Befehl nicht ändern möchte? Was ist, wenn ich denselben Befehl weiterhin verwenden möchte? Wie kann ich dafür sorgen, dass Dinge „nur funktionieren“, ohne dass dieser Fehler auftritt? Welche Lösungen sind verfügbar?

Kommentare

  • Nützliche Lektüre: Bash FAQ 95 . Ohne Ihren Befehl zu ändern ‚ Sie können nicht viel tun, außer neu zu kompilieren, um die maximale Größe Ihrer Argumentliste zu erhöhen, oder Ihre Verzeichnisstruktur so zu ändern, dass weniger Dateien vorhanden sind.
  • @ jw013 Basierend auf der Linux-Kernel-Version kann die Argumentliste möglicherweise erweitert werden. Weitere Informationen zur Änderung finden Sie unter unix.stackexchange.com/a/45161/8979 Neuere Systeme.
  • @UlrichDangel, Yup, es ist möglich! Siehe meine Antwort; meine Antwort zeigt, wie es geht (auf L. inux, mit einem ausreichend aktuellen Kernel).

Antwort

Unter Linux der maximale Speicherplatz für Befehle Argumente sind 1/4 der Menge des verfügbaren Stapelspeichers. Eine Lösung besteht also darin, den für den Stapel verfügbaren Speicherplatz zu erhöhen.

Kurzversion: Führen Sie etwa

ulimit -s 65536 

Längere Version aus : Der Standardspeicherplatz für den Stapel beträgt ca. 8192 KB. Sie können den verfügbaren Speicherplatz wie folgt anzeigen:

$ ulimit -s 8192 

Wählen Sie eine größere Anzahl aus und legen Sie den verfügbaren Speicherplatz für den Stapel fest. Wenn Sie beispielsweise versuchen möchten, bis zu 65536 KB für den Stapel zuzulassen, führen Sie Folgendes aus:

$ ulimit -s 65536 

Möglicherweise müssen Sie damit herumspielen, wie groß dies sein muss mit Versuch und Irrtum sein. In vielen Fällen ist dies eine schnelle und schmutzige Lösung, bei der der Befehl nicht mehr geändert und die Syntax von find, xargs usw. (obwohl mir klar ist, dass dies andere Vorteile bietet).

Ich glaube, dass dies Linux-spezifisch ist. Ich vermute, dass es auf keinem anderen Unix-Betriebssystem (nicht getestet) hilft.

Kommentare

  • Sie können auf diese Weise überprüfen, ob es funktioniert hat : $ getconf ARG_MAX 2097152 $ ulimit -s 65535 $ getconf ARG_MAX 16776960
  • Bedeutet dies, dass die Befehlszeilengröße sein wird, wenn ich die Stapelgröße mit ulimit -s unlimited unbegrenzt mache auch unbegrenzt?

Antwort

Anstelle von ls */*/*/*/*.jpg, Versuchen Sie:

echo */*/*/*/*.jpg | xargs ls 

xargs (1) weiß, wie viele Argumente sich maximal auf dem System befinden, und bricht die Standardeingabe auf, um die angegebene Befehlszeile mehrmals mit nicht mehr Argumenten als dieser Grenze aufzurufen, unabhängig davon, um was es sich handelt (Sie können sie auch mit -n Option).

Angenommen, das Limit beträgt 3 Argumente und Sie haben fünf Dateien. In diesem Fall führt xargs ls zweimal aus:

  1. ls 1.jpg 2.jpg 3.jpg
  2. ls 4.jpg 5.jpg

Oft ist dies perfekt geeignet, aber nicht immer – zum Beispiel können Sie nicht Verlassen Sie sich darauf, dass ls (1) alle Einträge für Sie richtig sortiert , da jede einzelne ls -Invocation sortiert nur die Teilmenge der Einträge, die ihm von xargs gegeben wurden.

Obwohl Sie das von anderen vorgeschlagene Limit überschreiten können, gibt es immer noch ein Limit – und eines Tages wird Ihre JPG-Sammlung wieder herauswachsen. Sie sollten Ihre Skripte darauf vorbereiten, mit einer unendlichen Zahl umzugehen …

Kommentare

  • Vielen Dank für die Idee! Dies ist keine schlechte Problemumgehung. Zwei Einschränkungen: 1. Dies wirkt sich auf Verzeichnisse und Dateinamen aus, deren Name Leerzeichen enthält, sodass ‚ kein perfekter Ersatz ist. 2. Wird das gleiche Problem mit Argument list too long auftreten, aber für echo anstelle von ls in Shells, in denen echo kein in die Shell integrierter Befehl ist? (Vielleicht ist ‚ in den meisten Shells kein Problem, also ist ‚ irrelevant.)
  • Ja Sonderzeichen in Dateinamen sind ein Problem. Am besten verwenden Sie find mit dem Prädikat -print0 – und leiten die Ausgabe an xargs mit der Option -0.echo ist eine integrierte Shell und leidet nicht unter der Befehlszeilenbeschränkung von exec (3).
  • Dies funktioniert mit Befehlen, die das Variablenargument als letzten Parameter erwarten, z. B. für ls. Was kann ich jedoch tun, wenn ich mv viele Dateien in ein einziges Verzeichnis, z mv * destdir? Wenn * dem “ zu viele Argumente “ Fehler gibt, kann ich ‚ xargs, um die Pfade als erste an mv zu übergeben, oder kann ich?
  • Überprüfen Sie die Manpage auf Ihrem System auf xargs – unter FreeBSD hilft beispielsweise die -J Sie mit dieser Aufgabe. Wenn dies auf Ihrem Betriebssystem nicht möglich ist, müssen Sie ‚ ein benutzerdefiniertes Skript schreiben, um die Argumente neu zu ordnen. So etwas wie: destdir=$1; shift; mv "$@" "$destdir". Geben Sie dieses neue Skript dann an xargs: .... | xargs newscript $destdir

Antwort

Dieser Linux Journal-Artikel enthält 4 Lösungen. Nur die vierte Lösung beinhaltet keine Änderung des Befehls:

Bei Methode 4 wird die Anzahl der Seiten, die im Kernel für die Befehlszeile zugewiesen sind, manuell erhöht Argumente. Wenn Sie sich die Datei include / linux / binfmts.h ansehen, finden Sie oben Folgendes:

/* * MAX_ARG_PAGES defines the number of pages allocated for arguments * and envelope for the new program. 32 should suffice, this gives * a maximum env+arg of 128kB w/4KB pages! */ #define MAX_ARG_PAGES 32 

Um den Speicherplatz zu erhöhen Für die Befehlszeilenargumente müssen Sie lediglich den Wert MAX_ARG_PAGES mit einer höheren Nummer versehen. Sobald diese Bearbeitung gespeichert ist, kompilieren Sie sie einfach neu, installieren Sie sie und starten Sie sie wie gewohnt neu in den neuen Kernel.

Auf meinem eigenen Testsystem konnte ich alle meine Probleme lösen, indem ich diesen Wert auf 64 erhöhte Beim Testen habe ich seit dem Wechsel kein einziges Problem festgestellt. Dies ist völlig zu erwarten, da selbst wenn MAX_ARG_PAGES auf 64 gesetzt ist, die längste mögliche Befehlszeile, die ich erzeugen könnte, nur 256 KB Systemspeicher belegen würde – nach den heutigen Systemhardwarestandards nicht sehr viel

Die Vorteile von Methode 4 liegen auf der Hand. Sie können den Befehl jetzt einfach wie gewohnt ausführen und er wird erfolgreich ausgeführt. Die Nachteile liegen auf der Hand. Wenn Sie den verfügbaren Speicher erhöhen Über die Größe des verfügbaren Systemspeichers hinaus können Sie einen DOS-Angriff auf Ihr eigenes System erstellen und zum Absturz bringen. Insbesondere auf Mehrbenutzersystemen kann bereits eine geringfügige Erhöhung erhebliche Auswirkungen haben, da jedem Benutzer dann der zugewiesen wird Zusätzlicher Speicher. Testen Sie daher immer ausgiebig in Ihrer eigenen Umgebung, da dies der sicherste Weg ist, um festzustellen, ob Methode 4 für Sie eine praktikable Option ist.

Ich bin damit einverstanden, dass die Einschränkung ernsthaft ärgerlich ist.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.