it-swarm.com.de

Argumentliste zu lang für ls

Ich erhalte die folgende Fehlermeldung, wenn ich versuche, ls *.txt | wc -l ein Verzeichnis, das viele Dateien enthält:

-bash: /bin/ls: Argument list too long

Hängt der Schwellenwert dieser "Argumentliste" von der Distribution oder der Computerspezifikation ab? Normalerweise würde ich das Ergebnis eines so großen Ergebnisses an einige andere Befehle weiterleiten (wc -l zum Beispiel), also beschäftige ich mich nicht mit den Grenzen des Terminals.

51
user19016

Ihre zu lange Argumentliste für Fehlermeldungen stammt aus dem ***** von ls *.txt.

Diese Grenze ist eine Sicherheit sowohl für Binärprogramme als auch für Ihren Kernel. Weitere Informationen dazu und zur Verwendung und Berechnung finden Sie unter ARG_MAX, maximale Länge der Argumente für einen neuen Prozess .

Es gibt keine solche Begrenzung für die Rohrgröße. Sie können also einfach diesen Befehl eingeben:

find -type f -name '*.txt'  | wc -l

NB: Unter modernem Linux werden seltsame Zeichen in Dateinamen (wie Zeilenumbrüche) mit Tools wie ls oder find maskiert, aber immer noch von ***** angezeigt. Wenn Sie unter einem alten Unix arbeiten, benötigen Sie diesen Befehl

find -type f -name '*.txt' -exec echo \;  | wc -l

NB2: Ich habe mich gefragt, wie man eine Datei mit einem Zeilenumbruch im Namen erstellen kann. Es ist nicht so schwer, wenn Sie den Trick kennen:

touch "hello
world"
53
Coren

Dies hängt hauptsächlich von Ihrer Version des Linux-Kernels ab.

Sie sollten in der Lage sein, das Limit für Ihr System durch Ausführen zu erkennen

getconf ARG_MAX

hier erfahren Sie, wie viele Bytes eine Befehlszeile maximal haben kann, nachdem sie von der Shell erweitert wurde.

Unter Linux <2.6.23 beträgt das Limit normalerweise 128 KB.

Unter Linux> = 2.6.25 beträgt das Limit entweder 128 KB oder 1/4 Ihrer Stapelgröße (siehe ulimit -s), je nachdem, welcher Wert größer ist.

Weitere Informationen finden Sie in der Manpage execve (2) .


Leider Rohrleitungen ls *.txt wird das Problem nicht beheben, da das Limit im Betriebssystem und nicht in der Shell liegt.

Die Shell erweitert das *.txt, versucht dann anzurufen

exec("ls", "a.txt", "b.txt", ...)

und Sie haben so viele Dateien, die mit *.txt dass Sie das 128-KB-Limit überschreiten.

Du musst so etwas tun

find . -maxdepth 1 -name "*.txt" | wc -l

stattdessen.

(Und siehe Shawn J. Goffs Kommentare unten zu Dateinamen, die Zeilenumbrüche enthalten.)

11
Mikel

Eine weitere Problemumgehung:

ls | grep -c '\.txt$'

Obwohl ls mehr Ausgabe erzeugt als ls *.txt (Oder versucht zu produzieren), stößt es nicht auf das Problem "Argument zu lang", weil Sie nicht übergeben any Argumente für ls. Beachten Sie, dass grep einen regulären Ausdruck anstelle eines Dateimatching-Musters verwendet.

Vielleicht möchten Sie verwenden:

ls -U | grep -c '\.txt$'

(Vorausgesetzt, Ihre Version von ls unterstützt diese Option). Dies weist ls an, die Ausgabe nicht zu sortieren, was sowohl Zeit als auch Speicher sparen könnte - und in diesem Fall spielt die Reihenfolge keine Rolle, da Sie nur Dateien zählen. Die Ressourcen, die für das Sortieren der Ausgabe aufgewendet werden, sind normalerweise nicht signifikant. In diesem Fall wissen wir jedoch bereits, dass Sie eine sehr große Anzahl von *.txt - Dateien haben.

Und Sie sollten in Betracht ziehen, Ihre Dateien neu zu organisieren, damit Sie nicht so viele in einem einzigen Verzeichnis haben. Dies kann machbar sein oder nicht.

9
Keith Thompson

MAX_ARG_PAGES scheint ein Kernel-Parameter zu sein. Die Verwendung von find und xargs ist eine typische Kombination, um dieses Limit zu erreichen, aber ich bin nicht sicher, ob es für wc funktioniert.

Piping der Ausgabe von find . -name \*\.txt zu einer Datei und das Zählen der Zeilen in dieser Datei sollte als Problemumgehung dienen.

1
Bram

Das mag schmutzig sein, aber es funktioniert für meine Bedürfnisse und innerhalb meiner Kompetenz. Ich glaube nicht, dass es sehr schnell geht, aber es hat mir erlaubt, mit meinem Tag weiterzumachen.

ls | grep jpg | <something>

Ich bekam eine 90.000 lange Liste von JPGs und leitete sie an avconv weiter, um einen Zeitraffer zu generieren.

Ich habe zuvor ls * .jpg | verwendet avconv bevor ich auf dieses Problem gestoßen bin.

1