Como o comando find sabe quantos argumentos para alimentar com “-exec… {} +”?

1

Em um comando como este:

find /data ! -type d -exec rm -f {} +

o + é para execução em lote de rm -f . find deve agrupar tantos argumentos quanto possível. Mas como sabe o limite?

    
por Tomasz 11.11.2018 / 23:10

2 respostas

3

O limite para a capacidade de find de argumentos em lote, ao invocar um comando especificado por -exec com + , é normalmente determinado pelo kernel: é o tamanho máximo dos argumentos fornecidos para o exec família de funções. O POSIX define duas maneiras de descobrir um valor relacionado a isso, o tamanho máximo dos argumentos e ambiente dado a uma chamada exec .

O primeiro deles é uma constante, que, portanto, acaba “cozido” em executáveis quando eles são construídos; é a constante ARG_MAX em limits.h :

Maximum length of argument to the exec functions including environment data.

O segundo deles está disponível em tempo de execução: envolve o uso de a função sysconf , especificamente com o argumento _SC_ARG_MAX .

O limite definido por ARG_MAX (que se aplica a ambas as abordagens descritas acima, já que ambos fornecem acesso à variável “{ARG_MAX}”) é especificado por POSIX , em relação a -exec :

The size of any set of two or more pathnames shall be limited such that execution of the utility does not cause the system's {ARG_MAX} limit to be exceeded.

O mesmo é válido para xargs :

The xargs utility shall limit the command line length such that when the command line is invoked, the combined argument and environment lists (see the exec family of functions in the System Interfaces volume of POSIX.1-2017) shall not exceed {ARG_MAX}-2048 bytes.

Várias implementações aplicam esses limites de várias maneiras, às vezes aplicando valores menores do que as constantes acima indicariam. Por exemplo, o OpenBSD find verifica sysconf , para determinar o comprimento máximo da linha de comando, mas também limita arbitrariamente o número de argumentos para 5000; veja o código fonte para detalhes (graças a mosvy para a referência). find do GNU verifica sysconf e volta se necessário para ARG_MAX ou um limite find -specificado; Além disso, ele adiciona o headroom de 2048 bytes especificado para xargs (o% GNU find e xargs compartilham sua implementação aqui).

Os kernels específicos também podem adicionar suas próprias torções. O que define o tamanho máximo para um único argumento de comando? discute isso para o Linux. O Solaris aparentemente requer diferentes limites a serem considerados, dependendo se o processo gerado (não o processo find ou xargs , mas o futuro processo filho) é de 32 ou 64 bits, devido à variação dos requisitos de pilha; veja libfind para detalhes (graças a schily para o ponteiro). O Hurd não limita os argumentos .

    
por 11.11.2018 / 23:16
0

Mencionei recentemente as regras gerais aqui:

Lista de argumentos erro muito longo com makefile

Uma implementação funcional dessa regra está no meu próprio libfind : link

O principal problema aqui é que libfind precisa saber o tamanho atual do ambiente e se o programa que está sendo chamado é um programa de 32 ou 64 bits, pois existem diferentes limites ...

libfind faz distinção de 32/64 bits porque antes eu frequentemente atingia o limite ao chamar find -name '*.c' -exec count -t {} + para obter a contagem de linhas de origem para projetos maiores quando libfind era usado de um shell de 64 bits ao chamar o Programa de 32 bits count .

A implementação de solaris find não precisa fazer essa distinção, pois o Solaris não envia uma descoberta de 64 bits e, portanto, o uso do limite de 32 bits funcionaria em qualquer caso - mesmo que não use o máximo possível de arg tamanho da lista.

BTW: para find é improvável que o limite adicional desnecessário para um único argumento no Linux (128k) se aplique. Para make , esse é um problema real, já que toda a linha de comando do shell é passada como um único argumento. Por outro lado, make não verifica antecipadamente, pois make não inclui código para dividir comandos longos.

P.S .: Acabei de descobrir um limite engraçado no Solaris: ambos, xargs e find do Solaris chamam seus programas via execvp() de libc e, caso o programa a ser chamado seja um srcipt sem #! , o execvp() implementation chama o shell para o script e reordena os argumentos usando uma matriz de tamanho fixo. Como esse array tem apenas 255 entradas, tanto xargs como find limitam seus argumentos para 255, caso o comando seja um script de shell tão simples. Se os programas forem um script e o arglist contiver mais de 255 argumentos, execvp() retornará E2BIG .

O problema aqui é: você não pode usar malloc() dentro de execvp() , pois execvp() pode ter sido chamado de um processo que foi criado por meio de vfork() . Se execvp() chamaria malloc() , isso resultaria em memória alocada inativa no pai ... chamando alloca() no outro lado sempre terá êxito, mas poderá levar a SIGSEGV caso o tamanho da pilha local seja excedido .

    
por 12.11.2018 / 00:01