“ Argumentlistan för lång ”: Hur hanterar jag den utan att ändra mitt kommando?

När jag kör ett kommando som ls */*/*/*/*.jpg får jag felet

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

Jag vet varför detta händer: det beror på att det finns en kärngräns på mängden utrymme för argument till ett kommando. Standardrådet är att ändra kommandot jag använder för att undvika att kräva så mycket utrymme för argument (använd find och xargs).

Vad händer om jag inte vill ändra kommandot? Vad händer om jag vill fortsätta använda samma kommando? Hur kan jag få saker att ”bara fungera” utan att få detta fel? Vilka lösningar finns?

Kommentarer

  • Användbar läsning: Bash FAQ 95 . Utan att ändra ditt kommando det ' är inte mycket du kan göra förutom att kompilera om du vill öka din maximala storlek på argumentlistan eller ändra din katalogstruktur så att det blir färre filer.
  • @ jw013 baserat på Linux-kärnversionen kan det vara möjligt att öka argumentlistan – se unix.stackexchange.com/a/45161/8979 för detaljer om förändringen i senaste system.
  • @UlrichDangel, Yup, det är möjligt! Se mitt svar; mitt svar visar hur man gör det (på L inux, med en tillräckligt nyligen kärna).

Svar

På Linux är det maximalt utrymme för kommando argument är 1/4 av mängden tillgängligt stackutrymme. Så, en lösning är att öka mängden ledigt utrymme för stacken.

Kort version: kör något som

ulimit -s 65536 

Längre version : Standardmängden tillgängligt utrymme för stacken är ungefär 8192 KB. Du kan se mängden tillgängligt utrymme enligt följande:

$ ulimit -s 8192 

Välj ett större antal och ställ in mängden ledigt utrymme för stacken. Om du till exempel vill försöka tillåta upp till 65536 kB för stacken, kör det här:

$ ulimit -s 65536 

Du kan behöva leka med hur stort detta behöver att vara med hjälp av försök och fel. I många fall är detta en snabb och smutsig lösning som eliminerar behovet av att ändra kommandot och utarbeta syntaxen för find, xargs etc. (även om jag inser att det finns andra fördelar med att göra det).

Jag tror att detta är Linux-specifikt. Jag misstänker att det förmodligen inte kommer att hjälpa någon annan Unix-operativsystem (inte testad).

Kommentarer

  • Du kan verifiera så här att det fungerade : $ getconf ARG_MAX 2097152 $ ulimit -s 65535 $ getconf ARG_MAX 16776960
  • Betyder detta att om jag gör stapelstorleken obegränsad med ulimit -s unlimited kommer kommandoradsstorleken att vara obegränsat också?

Svara

I stället för ls */*/*/*/*.jpg, försök:

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

xargs (1) vet vad det maximala antalet argument är i systemet och kommer att bryta upp sin standardingång för att ringa den angivna kommandoraden flera gånger utan fler argument än den gränsen, oavsett vilken det är (du kan också ställa in den lägre än OS ”maximalt med -n option).

Antag till exempel att gränsen är 3 argument och att du har fem filer. I så fall kommer xargs att köra ls två gånger:

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

Ofta är det här perfekt, men inte alltid – till exempel kan du inte lita på att ls (1) sorterar alla poster åt dig ordentligt, eftersom varje separat ls -inbjudan kommer bara att sortera delmängden av poster som ges till den av xargs.

Även om du kan stöta på gränsen som föreslagits av andra, kommer det fortfarande att finnas en gräns – och någon dag kommer din JPG-samling att växa igen. Du bör förbereda dina skript för att hantera ett oändligt antal …

Kommentarer

  • Tack för idén! Det här är inte en dålig lösning. Två försiktighetsåtgärder: 1. Detta bryts mot kataloger och filnamn som har mellanslag i sitt namn, så det ' är inte ett perfekt substitut. 2. Kommer det att stöta på samma problem med Argument list too long, men för echo istället för ls, på skal där echo inte är ett inbyggt skalkommando? (Kanske är att ' inte är ett problem i de flesta skalen, så kanske att ' är irrelevant.)
  • Ja , specialtecken i filnamn är ett problem. Din bästa satsning är att använda find med -print0 predikat – och rör dess utdata till xargs med alternativet -0.echo är ett inbyggt skal och lider inte av kommandoradsbegränsningen på exec (3).
  • Detta fungerar med kommandon som förväntar sig att variabelargumentet är den sista parametern, till exempel för ls, men vad ska jag göra när jag vill mv många filer till en enda dir, t.ex. mv * destdir? Om * ger " för många args " -fel kan jag ' t gör xargs att passera banorna som första till mv på något sätt, eller kan jag?
  • Kontrollera man-sidan för xargs på ditt system – på FreeBSD, till exempel, hjälper -J du med den här uppgiften. Om det inte finns något sätt att göra detta på ditt operativsystem måste du ' skriva ett anpassat skript för att ordna om argumenten. Något som: destdir=$1; shift; mv "$@" "$destdir". Ge sedan det här nya skriptet till xargs: .... | xargs newscript $destdir

Svar

Denna Linux Journal-artikel ger 4 lösningar. Endast den fjärde lösningen innebär inte att kommandot ändras:

Metod # 4 innebär att manuellt ökar antalet sidor som tilldelas inom kärnan för kommandoraden argument. Om du tittar på filen include / linux / binfmts.h hittar du följande högst upp:

/* * 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 

För att öka mängden minne tillägnad kommandoradsargumenten behöver du helt enkelt ange MAX_ARG_PAGES-värdet med ett högre nummer. När denna redigering har sparats, kompilerar du helt enkelt, installerar och startar om i den nya kärnan som du skulle göra normalt.

På mitt eget testsystem lyckades jag lösa alla mina problem genom att höja detta värde till 64. Efter omfattande testning, jag har inte upplevt ett enda problem sedan bytet. Detta förväntas helt eftersom även med MAX_ARG_PAGES inställd på 64, skulle den längsta möjliga kommandoraden jag kunde producera bara uppta 256 kB systemminne – inte så mycket av dagens systemhårdvarustandarder .

Fördelarna med metod nr 4 är tydliga. Du kan nu helt enkelt köra kommandot som vanligt, och det slutfördes framgångsrikt. Nackdelarna är lika tydliga. Om du ökar mängden tillgängligt minne till kommandoraden bortom mängden tillgängligt systemminne kan du skapa en DOS-attack på ditt eget system och få det att krascha. I synnerhet på fleranvändarsystem kan till och med en liten ökning ha en betydande inverkan eftersom varje användare sedan tilldelas ytterligare minne. Testa därför noggrant i din egen miljö, eftersom det här är det säkraste sättet att avgöra om metod nr 4 är ett genomförbart alternativ för dig.

Jag håller med om att begränsningen är allvarligt irriterande.

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *