"Elenco argomenti troppo lungo": come posso gestirlo senza cambiare il mio comando?


18

Quando eseguo un comando simile ls */*/*/*/*.jpg, ottengo l'errore

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

So perché questo accade: è perché esiste un limite del kernel sulla quantità di spazio per gli argomenti di un comando. Il consiglio standard è quello di cambiare il comando che uso, per evitare di richiedere così tanto spazio per gli argomenti (ad esempio, use finde xargs).

Cosa succede se non desidero modificare il comando? Cosa succede se voglio continuare a utilizzare lo stesso comando? Come posso rendere le cose "semplicemente funzionanti", senza ottenere questo errore? Quali soluzioni sono disponibili?


Lettura utile: FAQ Bash 95 . Senza modificare il comando non c'è molto altro da fare oltre a ricompilare per aumentare la dimensione massima dell'elenco argomenti o modificare la struttura della directory in modo che ci siano meno file.
jw013,

1
@ jw013 in base alla versione del kernel linux potrebbe essere possibile aumentare l'elenco degli argomenti - consultare unix.stackexchange.com/a/45161/8979 per dettagli sulla modifica dei sistemi recenti.
Ulrich Dangel,

@UlrichDangel, Yup, è possibile! Vedi la mia risposta; la mia risposta mostra come farlo (su Linux, con un kernel abbastanza recente).
DW

Risposte:


26

Su Linux, la quantità massima di spazio per gli argomenti dei comandi è 1/4 della quantità di spazio dello stack disponibile. Quindi, una soluzione è aumentare la quantità di spazio disponibile per lo stack.

Versione breve: esegui qualcosa di simile

ulimit -s 65536

Versione più lunga: la quantità predefinita di spazio disponibile per lo stack è simile a 8192 KB. Puoi vedere la quantità di spazio disponibile, come segue:

$ ulimit -s
8192

Scegli un numero più grande e imposta la quantità di spazio disponibile per la pila. Ad esempio, se si desidera provare a consentire fino a 65536 KB per lo stack, eseguire questo:

$ ulimit -s 65536

Potrebbe essere necessario giocare con quanto deve essere grande, usando tentativi ed errori. In molti casi, si tratta di una soluzione rapida-and-dirty che eliminerà la necessità di modificare il comando e il lavoro fuori la sintassi find, xargsecc (anche se mi rendo conto che ci sono altri vantaggi a farlo).

Credo che questo sia specifico di Linux. Sospetto che probabilmente non aiuterà su nessun altro sistema operativo Unix (non testato).


1
Puoi verificare in questo modo che ha funzionato: $ getconf ARG_MAX 2097152 $ ulimit -s 65535 $ getconf ARG_MAX 16776960
Alex

2

Questo articolo su Linux Journal offre 4 soluzioni. Solo la quarta soluzione non comporta la modifica del comando:

Il metodo n. 4 prevede l'aumento manuale del numero di pagine allocate all'interno del kernel per gli argomenti della riga di comando. Se guardi il file include / linux / binfmts.h, troverai quanto segue nella parte superiore:

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

Per aumentare la quantità di memoria dedicata agli argomenti della riga di comando, è sufficiente fornire al valore MAX_ARG_PAGES un numero maggiore. Una volta salvata questa modifica, è sufficiente ricompilare, installare e riavviare nel nuovo kernel come si farebbe normalmente.

Sul mio sistema di test sono riuscito a risolvere tutti i miei problemi aumentando questo valore a 64. Dopo test approfonditi, non ho riscontrato un singolo problema dal passaggio. Questo è del tutto previsto poiché, anche se MAX_ARG_PAGESimpostato su 64, la riga di comando più lunga possibile che potrei produrre occuperebbe solo 256 KB di memoria di sistema, non molto per gli standard hardware di sistema di oggi.

I vantaggi del metodo n. 4 sono evidenti. Ora puoi semplicemente eseguire il comando come faresti normalmente e si completa correttamente. Gli svantaggi sono ugualmente chiari. Se si aumenta la quantità di memoria disponibile nella riga di comando oltre la quantità di memoria di sistema disponibile, è possibile creare un attacco DOS sul proprio sistema e causarne l'arresto anomalo. In particolare sui sistemi multiutente, anche un piccolo aumento può avere un impatto significativo perché a ogni utente viene assegnata la memoria aggiuntiva. Pertanto, esegui sempre un test approfondito nel tuo ambiente, poiché questo è il modo più sicuro per determinare se il Metodo n. 4 è un'opzione praticabile per te.

Concordo sul fatto che la limitazione sia seriamente fastidiosa.


1

Invece di ls */*/*/*/*.jpg, prova:

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

xargs(1) sa quale sia il numero massimo di argomenti sul sistema e interromperà l'input standard per chiamare più volte la riga di comando specificata senza più argomenti di quel limite, qualunque esso sia (puoi anche impostarlo su un valore inferiore a il massimo del SO usando l' -nopzione).

Ad esempio, supponiamo, il limite è di 3 argomenti e hai cinque file. In tal caso xargsverrà eseguito lsdue volte:

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

Spesso questo è perfettamente adatto, ma non sempre - ad esempio, non puoi fare affidamento sul ls(1) ordinamento di tutte le voci per te correttamente, poiché ogni ls-invocazione separata ordinerà solo il sottoinsieme di voci fornite da xargs.

Anche se puoi superare il limite come suggerito da altri, ci sarà ancora un limite - e un giorno la tua raccolta di JPG lo supererà di nuovo. Dovresti preparare i tuoi script per gestire un numero infinito ...


Grazie per l'idea! Questa non è una brutta soluzione. Due avvertenze: 1. Questo si interrompe su directory e nomi di file che hanno spazi nel loro nome, quindi non è un sostituto perfetto. 2. Si verificherà lo stesso problema con Argument list too long, ma echoinvece che con ls, su shell dove echonon è presente un comando incorporato di shell? (Forse non è un problema nella maggior parte delle shell, quindi forse è irrilevante.)
DW,

1
Sì, i caratteri speciali nei nomi dei file sono un problema. La tua scommessa migliore è usare findcon il -print0predicato e convogliare il suo output xargscon l' -0opzione. echoè una shell integrata e non soffre della limitazione della riga di comando di exec(3).
Mikhail T.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.