Lembre-se de três pontos principais ao enfrentar um Argument list too longerro:
O comprimento dos argumentos da linha de comando é limitado pela ARG_MAXvariável, que, por definição do POSIX, é "... [m] comprimento máximo do argumento para as funções exec, incluindo dados do ambiente" (ênfase adicionada) ". Ou seja, quando o shell executa um comando não comando -built-it, ele deve chamar um dos exec()para gerar o processo desse comando, e é aí que ARG_MAXentra em cena.Além disso, o nome ou o caminho do próprio comando (por exemplo /bin/echo) desempenha um papel.
Os comandos internos do shell são executados pelo shell, o que significa que o shell não usa a exec()família de funções e, portanto, não é afetado pela ARG_MAXvariável.
Certos comandos, como xargse findconhecem as ARG_MAXvariáveis e executam ações repetidamente sob esse limite
Pelos pontos acima e como mostrado na excelente resposta de Kusalananda sobre questões relacionadas, isso Argument list too longtambém pode ocorrer quando o ambiente é grande. Portanto, levando em consideração que o ambiente de cada usuário pode variar e o tamanho do argumento em bytes é relevante, é difícil criar um único número de arquivos / argumentos.
Como lidar com esse erro?
O principal é não se concentrar no número de arquivos, mas se o comando que você vai usar envolve ou não uma exec()família de funções e tangencialmente - o espaço da pilha.
Use built-ins do shell
Como discutido anteriormente, os embutidos no shell são imunes ao ARG_MAXlimite, ou seja, forloops, whileloops, embutidos echoe embutidos printf- todos terão bom desempenho.
for i in /path/to/dir/*; do cp "$i" /path/to/other/dir/; done
Em questões relacionadas à exclusão de arquivos, havia uma solução como essa:
printf '%s\0' *.jpg | xargs -0 rm --
Observe que isso usa o shell interno printf. Se estivermos chamando o externo printf, isso envolverá exec(), portanto, falhará com grande número de argumentos:
$ /usr/bin/printf "%s\0" {1..7000000}> /dev/null
bash: /usr/bin/printf: Argument list too long
matrizes de bash
De acordo com uma resposta de jlliagre, bashnão impõe limites às matrizes, portanto, a criação de uma matriz de nomes de arquivos e o uso de fatias por iteração de loop também podem ser feitos, como mostra a resposta de danjpreron :
files=( /path/to/old_dir/*.prj )
for((I=0;I<${#files[*]};I+=1000)); do
cp -t /path/to/new_dir/ "${files[@]:I:1000}"
done
Isso, no entanto, tem limitações de ser específico do bash e não POSIX.
Aumentar o espaço da pilha
Às vezes você pode ver as pessoas sugerem aumentar o espaço de pilha com ulimit -s <NUM>; no Linux, o valor ARG_MAX é 1/4 do espaço da pilha para cada programa, o que significa que aumentar o espaço da pilha aumenta proporcionalmente o espaço para argumentos.
# getconf reports value in bytes, ulimit -s in kilobytes
$ getconf ARG_MAX
2097152
$ echo $(( $(getconf ARG_MAX)*4 ))
8388608
$ printf "%dK\n" $(ulimit -s) | numfmt --from=iec --to=none
8388608
# Increasing stack space results in increated ARG_MAX value
$ ulimit -s 16384
$ getconf ARG_MAX
4194304
De acordo com a resposta de Franck Dernoncourt , que cita o Linux Journal, também é possível recompilar o kernel do Linux com maior valor para o máximo de páginas de memória para argumentos, no entanto, isso é mais trabalhoso do que o necessário e abre potencial para explorações, conforme mencionado no artigo do Linux Journal.
Evite concha
Outra maneira, é usar pythonou python3que vem por padrão com o Ubuntu. O exemplo python + here-doc abaixo, é algo que eu pessoalmente usei para copiar um grande diretório de arquivos em algum lugar na faixa de 40.000 itens:
$ python <<EOF
> import shutil
> import os
> for f in os.listdir('.'):
> if os.path.isfile(f):
> shutil.copy(f,'./newdir/')
> EOF
Para percursos recursivos, você pode usar os.walk .
Veja também: