Linha de comando Bash e limite de entrada

91

Existe algum tipo de limite de caractere imposto no bash (ou outros shells) por quanto tempo uma entrada pode ter? Em caso afirmativo, qual é o limite de caracteres?

Ou seja, é possível escrever um comando em bash que seja muito longo para a linha de comando ser executado? Se não houver um limite obrigatório, existe um limite sugerido?

Derek Halden
fonte
2
O limite de entrada é muito diferente do limite de argumento no nível do sistema operacional (observe que algumas coisas além dos argumentos, como variáveis ​​de ambiente, também se aplicam a esse). O comando gerado passado para o sistema operacional pode ter mais ou menos caracteres do que o comando shell que o gerou.
Charles Duffy

Respostas:

129

O limite para o comprimento de uma linha de comando não é imposto pelo shell, mas pelo sistema operacional. Esse limite geralmente está na faixa de cem kilobytes. POSIX denota este limite ARG_MAXe em sistemas compatíveis com POSIX, você pode consultá-lo com

$ getconf ARG_MAX    # Get argument limit in bytes

Por exemplo, no Cygwin é 32000, e nos diferentes sistemas BSDs e Linux que eu uso é de 131072 a 2621440.

Se você precisa processar uma lista de arquivos que excedem esse limite, pode dar uma olhada no xargsutilitário, que chama um programa repetidamente com um subconjunto de argumentos que não excede ARG_MAX.

Para responder à sua pergunta específica, sim, é possível tentar executar um comando com uma lista de argumentos muito longa. O shell irá apresentar um erro com uma mensagem ao longo da "lista de argumentos muito longa".

Observe que a entrada para um programa (conforme lida em stdin ou qualquer outro descritor de arquivo) não é limitada (apenas por recursos de programa disponíveis). Portanto, se seu script de shell lê uma string em uma variável, você não está restrito por ARG_MAX. A restrição também não se aplica a shell-builtins.

Jens
fonte
Boa resposta, mas gostaria de um esclarecimento. Se eu cmd <<< "$LONG_VAR"obtiver uma construção e o valor LONG_VAR exceder o limite, meu comando explodirá?
Krzysztof Jabłoński
1
@ KrzysztofJabłoński Improvável, porque o conteúdo de LONG_VARé passado para stdin - e isso é feito inteiramente no shell; não é expandido como um argumento para cmd, então o limite ARG_MAX para fork () / exec () não entra em jogo. É fácil tentar você mesmo: crie uma variável com conteúdo superior a ARG_MAX e execute seu comando.
Jens
2
Aqui está o esclarecimento, para o registro: para um arquivo m4a 8 megabyte, eu fiz: blah="$(cat /home/schwager/Music/Recordings/20090420\ 131623.m4a)"; cat <<< $blah >/dev/null. Observe nenhum erro.
Mike S
4
Uma pequena advertência. As variáveis ​​de ambiente também contam. Página man do sysconf > É difícil usar ARG_MAX porque não é especificado quanto> do espaço de argumento para exec (3) é consumido pelas variáveis ​​de ambiente do usuário.
Gerrit
3
@ user188737 Acho que é uma grande advertência no BUGS . Por exemplo xargsno MacOS 10.12.6 limites quanto ele tenta colocar em um exec()a ARG_MAX - 4096. Portanto, o uso de scripts xargspode funcionar, até que um dia alguém coloque muita coisa no ambiente. Correndo para isso agora (contorne isso com xargs -s ???:).
neuralmer de
45

Ok, habitantes. Portanto, já há algum tempo aceitei os limites de comprimento de linha de comando como verdade. Então, o que fazer com as suposições de alguém? Naturalmente, verifique-os.

Tenho uma máquina Fedora 22 à minha disposição (ou seja: Linux com bash4). Eu criei um diretório com 500.000 inodes (arquivos) em cada um de 18 caracteres. O comprimento da linha de comando é de 9.500.000 caracteres. Criado assim:

seq 1 500000 | while read digit; do
    touch $(printf "abigfilename%06d\n" $digit);
done

E notamos:

$ getconf ARG_MAX
2097152

No entanto, posso fazer isso:

$ echo * > /dev/null

Mas isso falha:

$ /bin/echo * > /dev/null
bash: /bin/echo: Argument list too long

Posso executar um loop for:

$ for f in *; do :; done

que é outro shell embutido.

Leitura cuidadosa da documentação paraARG_MAX estados, comprimento máximo do argumento para as funções exec . Isso significa: Sem chamar exec, não há ARG_MAXlimitação. Portanto, isso explicaria por que os builtins do shell não são restritos por ARG_MAX.

E, de fato, posso conseguir lsmeu diretório se minha lista de argumentos tiver 1.09948 arquivos ou cerca de 2.089.000 caracteres (mais ou menos). Depois de adicionar mais um arquivo de nome de arquivo de 18 caracteres, no entanto, recebo um erro Lista de argumentos muito longa . Portanto, ARG_MAXestá funcionando conforme anunciado: o exec está falhando com mais de ARG_MAXcaracteres na lista de argumentos - incluindo, deve-se observar, os dados do ambiente.

Mike S
fonte
Hmm. Eu não tinha lido a resposta existente para sugerir que os builtins estavam sujeitos à restrição em questão, mas certamente posso ver como alguém poderia.
Charles Duffy
6
Sim, acho que é difícil lembrar - especialmente para afficianados de linha de comando mais recentes - que a situação de chamar um bash embutido versus fork / exec'ing um comando é diferente de maneiras não óbvias. Eu queria deixar isso bem claro. Uma pergunta que invariavelmente recebo em uma entrevista de emprego (como administrador de sistema do Linux) é: "Então, eu tenho um monte de arquivos em um diretório. Como faço para percorrer todos eles ..." O questionador está invariavelmente dirigindo em direção à linha limite de comprimento e quer uma solução find / while ou xargs. No futuro, direi: "ah, diabos - apenas use um loop for. Ele pode lidar com isso!" :-)
Mike S
@MikeS enquanto você poderia fazer um loop for, se você puder usar um combo find-xargs, você fará um fork muito menos e será mais rápido. ;-)
Lester Cheung
4
@LesterCheung for f in *; do echo $f; donenão bifurca (todos os builtins). Portanto, não sei se um combo find-xargs será mais rápido; não foi testado. Na verdade, não sei qual é o conjunto de problemas do OP. Talvez find /path/to/directorynão seja útil para ele porque retornará o nome do caminho do arquivo. Talvez ele goste da simplicidade de um for f in *loop. Independentemente disso, a conversa é sobre limite de entrada de linha - não eficiência. Portanto, vamos continuar no tópico, que diz respeito ao comprimento da linha de comando.
Mike S
FWIW, o problema, pelo que me lembro, era apenas tentar escrever um shell em C e determinar quanto tempo deveria permitir as entradas.
Derek Halden
-3

Existe um limite de buffer de algo como 1024. A leitura irá simplesmente travar no meio da colagem ou da entrada. Para resolver isso, use a opção -e.

http://linuxcommand.org/lc3_man_pages/readh.html

-e use Readline para obter a linha em um shell interativo

Mude sua leitura para ler -e e a interrupção da entrada de linha irritante vai embora.

Paul Kenjora
fonte
1
Não se trata de read: "Ou seja, é possível escrever um comando no bash que seja muito longo para a linha de comando ser executado?"
Chai T. Rex
@ ChaiT.Rex você está certo, mas aqui está o problema: tente executar o Bash interativamente sem Readline, ou seja bash --noediting, e no novo prompt tente executar o comando echo somereallylongword, onde alguma palavra realmente longa tem mais de 4090 caracteres. Tentei no Ubuntu 18.04, a palavra ficou truncada, então obviamente isso tem algo a ver com Readline não estar habilitado.
Amir
@Amir Interesting! Você está certo! Tentei editar a resposta, mas então percebi que a opção -e não se aplica ao bash neste contexto (no bash, ele sai do shell imediatamente em caso de erro). E não sei por que Paul girou para ler. De qualquer forma, há um limite de buffer de 4-5000 caracteres quando o bash é iniciado com --noreadline. Esse é um efeito colateral que eu não sabia ou esperava.
Mike S de