Když spustím příkaz jako ls */*/*/*/*.jpg
, zobrazí se chyba
-bash: /bin/ls: Argument list too long
Vím, proč se to děje: je to proto, že v jádře existuje limit na velikost prostoru pro argumenty příkazu. Standardní rada je změnit příkaz, který používám, aby nevyžadovalo tolik prostoru pro argumenty (např. Použijte find
a xargs
).
Co když nechci příkaz změnit? Co když chci používat stejný příkaz? Jak mohu věci „prostě fungovat“, aniž by se mi zobrazila tato chyba? Jaká řešení jsou k dispozici?
Komentáře
- Užitečné čtení: Bash FAQ 95 . beze změny příkazu ' toho není mnoho, co můžete udělat, kromě překompilování zvětšit maximální velikost seznamu argumentů nebo změnit strukturu adresáře tak, aby bylo méně souborů.
- @ jw013 na základě verze linuxového jádra je možné zvětšit seznam argumentů – podrobnosti o změně v unix.stackexchange.com/a/45161/8979 nedávné systémy.
- @UlrichDangel, jo, je to možné! Viz moje odpověď; moje odpověď ukazuje, jak to udělat (na L inux, s nedávným jádrem).
Odpověď
V systému Linux je maximální prostor pro příkaz argumenty je 1/4 množství dostupného prostoru zásobníku. Řešením je tedy zvětšit množství prostoru dostupného pro zásobník.
Krátká verze: spusťte něco jako
ulimit -s 65536
Delší verze : Výchozí velikost prostoru dostupného pro zásobník je něco jako 8192 kB. Velikost dostupného prostoru můžete zobrazit následovně:
$ ulimit -s 8192
Vyberte větší číslo a nastavte velikost dostupného prostoru pro zásobník. Chcete-li například zkusit povolit zásobníku až 65 536 kB, spusťte toto:
$ ulimit -s 65536
Možná si budete muset pohrát s tím, jak velké to potřebuje být pomocí pokusu a omylu. V mnoha případech se jedná o rychlé a špinavé řešení, které eliminuje potřebu upravit příkaz a vypracovat syntaxi find
, xargs
atd. (i když si uvědomuji, že to má i jiné výhody).
Věřím, že se jedná o Linux. Mám podezření, že pravděpodobně nepomůže žádnému jinému operačnímu systému Unix (netestováno).
Komentáře
- Takto můžete ověřit, že to fungovalo : $ getconf ARG_MAX 2097152 $ ulimit -s 65535 $ getconf ARG_MAX 16776960
- Znamená to, že když udělám neomezenou velikost zásobníku s
ulimit -s unlimited
velikost příkazového řádku bude neomezený také?
Odpověď
Místo ls */*/*/*/*.jpg
, zkuste:
echo */*/*/*/*.jpg | xargs ls
xargs
(1) ví, jaký je maximální počet argumentů v systému, a rozbije svůj standardní vstup, aby několikrát zavolal na zadaný příkazový řádek bez více argumentů, než je tento limit, ať už je jakýkoli (pomocí -n
option).
Předpokládejme například, že limit jsou 3 argumenty a máte pět souborů. V takovém případě xargs
provede ls
dvakrát:
-
ls 1.jpg 2.jpg 3.jpg
-
ls 4.jpg 5.jpg
Často je to naprosto vhodné, ale ne vždy – například nemůžete spoléhejte na ls
(1) třídění všech položek pro vás správně, protože každá samostatná ls
-invocation roztřídí pouze podmnožinu položek, které mu byly přiděleny xargs
.
Ačkoli můžete narazit na limit podle doporučení ostatních, stále bude existovat limit – a jednoho dne to vaše sbírka JPG přeroste znovu. Měli byste připravit své skripty, aby se vypořádaly s nekonečným počtem …
Komentáře
- Díky za nápad! To není špatné řešení. Dvě upozornění: 1. Toto naruší adresáře a názvy souborů, které mají v názvu mezery, takže ' to není dokonalá náhrada. 2. Narazí to na stejný problém s
Argument list too long
, ale proecho
místols
na skořápkách, kdeecho
není vestavěný příkaz prostředí? (Možná to ' ve většině mušlí není problém, takže to ' s není relevantní.) - Ano , speciální znaky v názvech souborů jsou problém. Nejlepším řešením je použít
find
s-print0
predikátem a přesměrovat jeho výstup doxargs
s volbou-0
.echo
je vestavěný shell a netrpí omezením příkazového řádkuexec
(3). - Toto funguje s příkazy, které očekávají argument proměnné jako poslední parametr, například pro
ls
, ale co mám dělat, když chcimv
mnoho souborů do jednoho adresáře, napřmv * destdir
? Pokud*
dá " příliš mnoho chyb ", mohu 'xargs
předat cesty jako první namv
nějak, nebo mohu? - Zkontrolujte manuálovou stránku
xargs
ve vašem systému – například na FreeBSD vám pomůže-J
vás s tímto úkolem. Pokud ve vašem operačním systému neexistuje žádný způsob, jak ' pro změnu pořadí argumentů napsat vlastní skript. Něco jako:destdir=$1; shift; mv "$@" "$destdir"
. Poté dejte tento nový skriptxargs
:.... | xargs newscript $destdir
odpověď
Tento článek Linux Journal obsahuje 4 řešení. Pouze čtvrté řešení nezahrnuje změnu příkazu:
Metoda č. 4 zahrnuje ruční zvýšení počtu stránek, které jsou v jádře přiděleny pro příkazový řádek argumenty. Pokud se podíváte na soubor include / linux / binfmts.h, najdete v horní části následující:
/* * 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
Aby se zvětšilo množství paměti vyhrazené pro argumenty příkazového řádku, stačí zadat hodnotu MAX_ARG_PAGES s vyšším číslem. Jakmile je tato úprava uložena, jednoduše ji znovu zkompilujte, nainstalujte a restartujte do nového jádra, jako byste to dělali normálně.
Ve svém vlastním testovacím systému se mi podařilo vyřešit všechny mé problémy zvýšením této hodnoty na 64. Po rozsáhlém testování, nezažil jsem od přepnutí jediný problém. To je zcela očekáváno, protože i při
MAX_ARG_PAGES
nastaveném na 64 by nejdelší možný příkazový řádek, jaký jsem mohl vyrobit, zabíral pouze 256 kB systémové paměti – dnešními hardwarovými standardy systému to moc není .Výhody metody č. 4 jsou jasné. Nyní můžete jednoduše spustit příkaz, jako byste normálně, a úspěšně se dokončí. Nevýhody jsou stejně jasné. Pokud zvýšíte množství dostupné paměti na příkazový řádek přesahující množství dostupné systémové paměti, můžete vytvořit útok DOS na svůj vlastní systém a způsobit jeho selhání. Zejména u víceuživatelských systémů může mít i malý nárůst významný dopad, protože každému uživateli je poté přidělen další paměť. Proto vždy důkladně otestujte ve svém vlastním prostředí, protože toto je nejbezpečnější způsob, jak zjistit, zda je pro vás metoda č. 4 životaschopnou volbou.
Souhlasím s tím, že omezení je vážně nepříjemné.