Ich hatte den Eindruck, dass die maximale Länge eines einzelnen Arguments hier nicht das Problem war, sondern vielmehr die Gesamtgröße des gesamten Argument-Arrays plus die Größe der Umgebung, die auf beschränkt ist ARG_MAX
. So dachte ich, dass so etwas gelingen würde:
env_size=$(cat /proc/$$/environ | wc -c)
(( arg_size = $(getconf ARG_MAX) - $env_size - 100 ))
/bin/echo $(tr -dc [:alnum:] </dev/urandom | head -c $arg_size) >/dev/null
Mit dem - 100
Sein mehr als genug, um den Unterschied zwischen der Größe der Umgebung in der Shell und dem echo
Prozess zu berücksichtigen. Stattdessen habe ich den Fehler bekommen:
bash: /bin/echo: Argument list too long
Nachdem ich eine Weile herumgespielt hatte, stellte ich fest, dass das Maximum eine ganze Hex-Größenordnung kleiner war:
/bin/echo \
$(tr -dc [:alnum:] </dev/urandom | head -c $(($(getconf ARG_MAX)/16-1))) \
>/dev/null
Wenn das Minuszeichen entfernt wird, wird der Fehler zurückgegeben. Scheinbar ist das Maximum für ein einzelnes Argument tatsächlich ARG_MAX/16
und die -1
Konten für das Nullbyte, das am Ende der Zeichenfolge im Argumentarray platziert wird.
Ein weiteres Problem ist, dass bei Wiederholung des Arguments die Gesamtgröße des Argument-Arrays näher sein kann ARG_MAX
, aber immer noch nicht ganz da ist:
args=( $(tr -dc [:alnum:] </dev/urandom | head -c $(($(getconf ARG_MAX)/16-1))) )
for x in {1..14}; do
args+=( ${args[0]} )
done
/bin/echo "${args[@]}" "${args[0]:6534}" >/dev/null
Die Verwendung von "${args[0]:6533}"
here verlängert das letzte Argument um 1 Byte und gibt den Argument list too long
Fehler aus. Es ist unwahrscheinlich, dass dieser Unterschied auf die Größe der gegebenen Umgebung zurückzuführen ist:
$ cat /proc/$$/environ | wc -c
1045
Fragen:
- Ist das korrekt oder gibt es irgendwo einen Fehler?
- Wenn nicht, ist dieses Verhalten irgendwo dokumentiert? Gibt es einen anderen Parameter, der das Maximum für ein einzelnes Argument definiert?
- Ist dieses Verhalten auf Linux (oder sogar bestimmte Versionen davon) beschränkt?
- Was erklärt die zusätzliche Diskrepanz von ~ 5 KB zwischen der tatsächlichen Maximalgröße des Argument-Arrays plus der ungefähren Größe der Umgebung und
ARG_MAX
?
Zusätzliche Information:
uname -a
Linux graeme-rock 3.13-1-amd64 #1 SMP Debian 3.13.5-1 (2014-03-04) x86_64 GNU/Linux
getconf ARG_MAX
hängt von der Stromstärke abulimit -s
. Setzen Sie es auf unbegrenzt und erhalten Sie eine erstaunliche 4611686018427387903 für ARG_MAX.Antworten:
Antworten
Der Parameter, der die maximale Größe für ein Argument definiert, ist
MAX_ARG_STRLEN
. Es gibt keine Dokumentation für diesen Parameter außer den Kommentaren inbinfmts.h
:Wie gezeigt, ist die Anzahl der Argumente für einen Befehl in Linux (sehr groß) begrenzt.
Eine Begrenzung der Größe eines einzelnen Arguments (die sich von der Gesamtbegrenzung für Argumente plus Umgebung unterscheidet) scheint für Linux spezifisch zu sein. Dieser Artikel enthält einen detaillierten Vergleich
ARG_MAX
und Entsprechungen zu Unix-ähnlichen Systemen.MAX_ARG_STRLEN
wird für Linux erörtert, auf anderen Systemen wird jedoch kein Äquivalent erwähnt.Der obige Artikel besagt auch, dass
MAX_ARG_STRLEN
er in Linux 2.6.23 eingeführt wurde, zusammen mit einer Reihe anderer Änderungen in Bezug auf Befehlsargumentmaxima (weiter unten beschrieben). Das Protokoll / Diff für das Commit finden Sie hier .Es ist immer noch nicht klar, was für die zusätzliche Diskrepanz zwischen dem Ergebnis
getconf ARG_MAX
und der tatsächlich maximal möglichen Größe von Argumenten plus Umgebung verantwortlich ist. Stephane Chazelas 'Antwort legt nahe, dass ein Teil des Raums durch Zeiger auf jede der Argument- / Umgebungszeichenfolgen erklärt wird. Meine eigene Untersuchung legt jedoch nahe, dass diese Zeiger nicht zu Beginn desexecve
Systemaufrufs erstelltE2BIG
werden, obwohl sie möglicherweise immer noch einen Fehler an den aufrufenden Prozess zurückgeben (obwohl Zeiger auf jedeargv
Zeichenfolge sicherlich später erstellt werden).Soweit ich sehen kann, sind die Zeichenfolgen auch zusammenhängend im Speicher, sodass hier keine Speicherlücken entstehen. Obwohl sehr wahrscheinlich ein Faktor in was auch immer sein wird den zusätzlichen Speicher aufbrauchen. Um zu verstehen, wie der zusätzliche Speicherplatz genutzt wird, ist eine genauere Kenntnis der Speicherzuweisung durch den Kernel erforderlich (eine nützliche Kenntnis, die ich später untersuchen und aktualisieren werde).
ARG_MAX Verwirrung
Seit Linux 2.6.23 (als Ergebnis dieses Commits ) wurden Änderungen an der Art und Weise vorgenommen, in der Befehlsargumentmaxima behandelt werden, wodurch sich Linux von anderen Unix-ähnlichen Systemen unterscheidet. Zusätzlich zum Hinzufügen von
MAX_ARG_STRLEN
und hängtMAX_ARG_STRINGS
das Ergebnis vongetconf ARG_MAX
der Stapelgröße ab und kann vonARG_MAX
in abweichenlimits.h
.Normalerweise das Ergebnis
getconf ARG_MAX
wird1/4
die Stack - Größe. Betrachten Sie die folgende inbash
mitulimit
der Stack - Größe zu bekommen:Das obige Verhalten wurde jedoch durch dieses Commit geringfügig geändert (hinzugefügt in Linux 2.6.25-rc4 ~ 121).
ARG_MAX
inlimits.h
dient nun als harte Untergrenze für das Ergebnis vongetconf ARG_MAX
. Wenn die Stapelgröße so eingestellt ist, dass1/4
die Stapelgröße kleiner alsARG_MAX
in istlimits.h
, wird derlimits.h
Wert verwendet:Beachten Sie außerdem, dass
ARG_MAX
die Größe des Stapels (RLIMIT_STACK
) die Obergrenze der Argument- / Umgebungsgröße darstellt, bevor sieE2BIG
zurückgegebengetconf ARG_MAX
wird , wenn die Stapelgröße auf einen niedrigeren Wert als den minimal möglichen Wert festgelegt wird (obwohl der Wert weiterhin in angezeigt wirdlimits.h
).Als letztes ist zu beachten, dass, wenn der Kernel ohne
CONFIG_MMU
(Unterstützung für Speicherverwaltungshardware) erstellt wird, die ÜberprüfungARG_MAX
deaktiviert ist, sodass das Limit nicht gilt. ObwohlMAX_ARG_STRLEN
undMAX_ARG_STRINGS
immer noch gelten.Weitere Lektüre
ARG_MAX
(und entsprechenden) Werten für andere Unix-ähnliche Systeme - http://www.in-ulm.de/~mascheck/various/argmax/MAX_ARG_STRLEN
anscheinend einen Fehler in Automake verursacht, bei dem Shell-Skripte in Makefiles eingebettet wurdensh -c
( http://www.mail-archive.com/[email protected]/msg05522.html)quelle
Im
eglibc-2.18/NEWS
Im
eglibc-2.18/debian/patches/kfreebsd/local-sysdeps.diff
Im
linux/include/uapi/linux/limits.h
Und
131072
ist dein$(getconf ARG_MAX)/16-1
, vielleicht solltest du bei 0 anfangen.Sie haben es mit glibc und Linux zu tun. Es wäre gut, getconf auch zu patchen, um den "richtigen"
ARG_MAX
Wert zurückzuerhalten.Bearbeiten:
Zur Klärung ein wenig (nach einer kurzen aber heißen Diskussion)
Die
ARG_MAX
in definierte Konstantelimits.h
gibt die maximale Länge eines mit exec übergebenen Arguments an.Der
getconf ARG_MAX
Befehl gibt den Maximalwert der Größe der kumulierten Argumente und der Umgebungsgröße zurück, die an exec übergeben wurden.quelle
eglibc-2.18/NEWS
Snippet? Es wäre gut, dies auf eine bestimmte Kernel-Version festzulegen.getconf ARG_MAX
geht um die kumulative Größe von arg + env (Variable in neuerem Linux, sieheulimit -s
und die andere Frage, die ich verlinkt habe), es geht nicht um die maximale Länge eines einzelnen Arguments, für das es keine sysconf / getconf-Abfrage gibt.@StephaneChazelas korrigiert mich daher zu Recht in den Kommentaren unten - die Shell selbst bestimmt in keiner Weise die von Ihrem System zulässige maximale Argumentgröße, sondern sie wird von Ihrem Kernel festgelegt.
Wie einige andere bereits gesagt haben, scheint der Kernel die maximale Argumentgröße, die Sie einem neuen Prozess von jedem anderen übergeben können, wenn Sie ihn zum ersten Mal ausführen, auf 128 KB zu begrenzen. Dieses Problem tritt speziell aufgrund der vielen verschachtelten
$(command substitution)
Subshells auf, die ausgeführt und die gesamte Ausgabe von einer zur nächsten übergeben werden müssen.Und dies ist eine wilde Vermutung, aber da die Diskrepanz von ~ 5 KB so nahe an der Seitengröße des Standardsystems zu liegen scheint, ist mein Verdacht, dass sie der Seite gewidmet ist, die für die
bash
Verarbeitung der von Ihnen$(command substitution)
benötigten Subshell verwendet wird, um letztendlich die Ausgabe und / oder das Ergebnis zu liefern den Funktionsstapel,array table
mit dem Sie Ihre Daten verknüpfen . Ich kann nur davon ausgehen, weder kommt frei.Im Folgenden wird gezeigt, dass es zwar etwas schwierig ist, beim Aufruf jedoch sehr große Shell-Variablenwerte an neue Prozesse weiterzugeben, sofern Sie es schaffen, sie zu streamen.
Zu diesem Zweck habe ich hauptsächlich Rohre verwendet. Aber ich habe auch das Shell-Array in einem
here-document
Punkt aufcat's stdin.
Ergebnisse unten ausgewertet .Aber noch eine letzte Anmerkung: Wenn Sie keinen besonderen Bedarf an portablem Code haben, fällt mir auf, dass dies
mapfile
Ihre Shell-Jobs ein wenig vereinfachen könnte.Möglicherweise könnten Sie dies verdoppeln und es dann erneut tun, wenn Sie es in Streams getan haben - ich bin nicht krankhaft genug, um es herauszufinden - aber auf jeden Fall funktioniert es, wenn Sie es streamen.
Ich habe versucht, das
printf
Generatorteil in Zeile zwei zu ändern :Es funktioniert auch:
Vielleicht bin ich ein bisschen krankhaft. Ich benutze
zero padding here
und addiere den vorherigen"$arg"
Wert zum aktuellen"$arg"
Wert. Ich komme weit über 6500 ...Und wenn ich die
cat
Zeile so ändere :Ich kann die Byteanzahl von erhalten.
wc.
Denken Sie daran, dies sind die Größen der einzelnen Schlüssel imargs
Array. Die Gesamtgröße des Arrays ist die Summe aller dieser Werte.quelle
echo $(tr -dc [:alnum:] </dev/urandom | head -c $(($(getconf ARG_MAX)*10))) >/dev/null
. Nur wenn Sie einen externen Befehl verwenden, liegt ein Problem vor.bash
komprimiert es irgendwie?printf
Ist ein Builtin so wird es nicht ausgeführt , und AFAICT, Ihrcat
bekommt kein Argument.