Lista de argumentos muito longa para ls

40

Eu recebo o seguinte erro ao tentar ls *.txt | wc -l um diretório que contém muitos arquivos:

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

O limite dessa "lista de argumentos" depende da distribuição ou da especificação do computador? Normalmente, eu canalizo o resultado de um resultado tão grande para alguns outros comandos ( wc -l , por exemplo), então não estou preocupado com os limites do terminal.

    
por zahypeti 18.05.2012 / 17:43

5 respostas

39

Sua mensagem de erro lista de argumentos por muito tempo vem do * de ls *.txt .

Esse limite é uma segurança para os programas binários e seu kernel. Você verá em esta página mais informações sobre o assunto e como ele é usado e computado.

Não existe tal limite no tamanho do tubo. Então você pode simplesmente emitir este comando:

find -type f -name '*.txt'  | wc -l

NB: No Linux moderno, caracteres estranhos em nomes de arquivos (como novas linhas) serão ignorados com ferramentas como ls ou find , mas ainda exibidos de * . Se você está em um Unix antigo, você precisará deste comando

find -type f -name '*.txt' -exec echo \;  | wc -l

NB2: Eu queria saber como se pode criar um arquivo com uma nova linha em seu nome. Não é tão difícil assim que você souber o truque:

touch "hello
world"
    
por 18.05.2012 / 18:32
11

Depende principalmente da sua versão do kernel do Linux.

Você deve conseguir ver o limite do seu sistema executando

getconf ARG_MAX

que informa o número máximo de bytes que uma linha de comando pode ter após ser expandida pelo shell.

No Linux < 2.6.23, o limite é geralmente 128 KB.

No Linux > = 2.6.25, o limite é 128 KB ou 1/4 do tamanho da sua pilha (veja ulimit -s ), o que for maior.

Consulte a página de manual execve (2) para todos os detalhes.

Infelizmente, canalizar ls *.txt não corrigirá o problema, porque o limite está no sistema operacional, não no shell.

O shell expande o *.txt , depois tenta chamar

exec("ls", "a.txt", "b.txt", ...)

e você tem muitos arquivos correspondentes a *.txt que você está excedendo o limite de 128 KB.

Você terá que fazer algo como

find . -maxdepth 1 -name "*.txt" | wc -l

em vez disso.

(E veja abaixo os comentários de Shawn J. Goff sobre nomes de arquivos que contêm novas linhas.)

    
por 18.05.2012 / 19:01
9

Outra solução alternativa:

ls | grep -c '\.txt$'

Mesmo que ls produza mais resultados que ls *.txt produz (ou tenta produzir), ele não é executado no problema "argumento muito longo", porque você não está passando nenhum argumentos para ls . Observe que grep usa uma expressão regular em vez de um padrão de correspondência de arquivo.

Você pode querer usar:

ls -U | grep -c '\.txt$'

(supondo que sua versão de ls suporte essa opção). Isso diz a ls para não classificar sua saída, o que poderia economizar tempo e memória - e nesse caso a ordem não importa, já que você está apenas contando arquivos. Os recursos gastos classificando a saída geralmente não são significativos, mas neste caso já sabemos que você tem um número muito grande de *.txt arquivos.

E você deve considerar reorganizar seus arquivos para que você não tenha tantos em um único diretório. Isso pode ou não ser viável.

    
por 19.05.2012 / 00:06
1

MAX_ARG_PAGES parece ser um parâmetro do kernel. Usar find e xargs é uma combinação típica para endereçar esse limite, mas não tenho certeza se funcionará para wc .

Pipar a saída de find . -name \*\.txt para um arquivo e contar as linhas nesse arquivo deve servir como uma solução alternativa.

    
por 18.05.2012 / 18:02
0

Isso pode ser sujo, mas funciona para as minhas necessidades e dentro da minha competência. Eu não acho que isso acontece muito rapidamente, mas me permitiu continuar com o meu dia.

ls | grep jpg | <something>

Eu estava conseguindo uma longa lista de 90.000 jpgs e enviando-os para gerar um timelapse.

Eu estava usando anteriormente ls * .jpg | avconv antes de me deparar com esta questão.

    
por 03.06.2018 / 00:40

Tags