Quando vai encontrar. -exec COMMAND {} + `executa COMMAND várias vezes?

8

Se eu fizer

find . -exec echo {} +

imprime todos os caminhos em uma linha, ou seja, o comando echoé executado apenas uma vez.

Mas de acordo com man find,

-exec command {} +
    ... the number of invocations of the command will 
be much  less  than  the  number  of matched files. ...

Parece que, em algumas circunstâncias, o comando será executado várias vezes. Estou certo? Por favor, exemplifique.

chama congelada
fonte

Respostas:

7

POSIX definiu find -exec utility_name [argumento ...] {} + como:

O final da expressão primária deve ser pontuado por um <semicolon> ou por um <plus-sign>. Somente um <plus-sign> que segue imediatamente um argumento contendo apenas os dois caracteres "{}" deve pontuar o final da expressão primária. Outros usos do <plus-sign> não devem ser tratados como especiais. Se a expressão primária for pontuada por um <semicolon>, o utilitário utility_name será invocado uma vez para cada nome de caminho e o primário será avaliado como verdadeiro se o utilitário retornar um valor zero como status de saída. Um nome ou argumento de utilidade contendo apenas os dois caracteres "{}" será substituído pelo nome do caminho atual. Se um nome ou argumento de utilitáriostring contém os dois caracteres "{}", mas não apenas os dois caracteres "{}", é definido pela implementação se find substitui esses dois caracteres ou usa a string sem alteração.

Se a expressão primária for pontuada por um <plus-sign>, o primário sempre será avaliado como verdadeiro, e os nomes de caminho para os quais o primário é avaliado serão agregados em conjuntos. O utilitário utility_name deve ser chamado uma vez para cada conjunto de nomes de caminho agregados. Cada chamada começará após a agregação do último nome do caminho no conjunto e deverá ser concluída antes da saída do utilitário find e antes do primeiro nome do caminho no próximo conjunto (se houver) ser agregado para este primário, mas, caso contrário, não será especificado se a chamada ocorre antes, durante ou após as avaliações de outras primárias. Se qualquer chamada retornar um valor diferente de zero como status de saída, a localização O utilitário retornará um status de saída diferente de zero. Um argumento contendo apenas os dois caracteres "{}" deve ser substituído pelo conjunto de nomes de caminho agregados, com cada nome de caminho passado como um argumento separado para o utilitário chamado na mesma ordem em que foi agregado. O tamanho de qualquer conjunto de dois ou mais nomes de caminho deve ser limitado, de modo que a execução do utilitário não faça com que o limite de {ARG_MAX} do sistema seja excedido . Se mais de um argumento contendo os dois caracteres "{}" estiver presente, o comportamento não será especificado.

Quando o comprimento definido do nome do arquivo encontrado excede o sistema ARG_MAX, o comando é executado.

Você pode ARG_MAXusar o getconf :

$ getconf ARG_MAX
2097152

Em alguns sistemas, o valor real de ARG_MAXpode ser diferente, você pode consultar aqui para mais detalhes.

cuonglm
fonte
Fiz um experimento usando find / -exec echo | wce medindo a proporção entre a contagem de caracteres e a linha. Descobri que o comprimento máximo da linha de comando usado findé significativamente menor que o limite POSIX teórico e muito mais próximo da Size of command buffer we are actually usinglinha na saída de xargs --show-limits. Isso vale para Linux e pode ser verdade para a implementação de Mac OS find, embora xargsnão imprima o valor no Mac OS. Alguma idéia de por que isso acontece?
Pqnet 29/08/14
--show-limitsnão é especificado pelo POSIX, a implementação do Mac OS xargsnão o suporta. find / -exec echo | wcnão vai funcionar. Lembre-se que ARG_MAXretornam bytes. E é o comprimento máximo dos argumentos para as exec(3)funções.
cuonglm
Eu sei que --show-limitsnão é POSIX, embora este não seja o tamanho máximo do argumento usado por find, que usa um valor menor. Não entendo por que você diz que find / -exec echo | wcisso não vai funcionar: na minha opinião, é uma boa maneira de ter uma estimativa do valor real (e pelo que posso ver, melhor do que usar getconf ARG_MAX). Além disso, meu sistema de arquivos é composto principalmente por caracteres ASCII, se não todos, portanto o número de caracteres é aproximadamente o mesmo que o número de bytes.
Pqnet 29/08/14
@pqnet: use find / -exec sh -c 'echo $@ | wc -c' _ {} +isntead.
cuonglm
desculpe, eu escrevi errado, eu realmente utilizadosfind / -exec echo {} + | wc -lc
pqnet
7

Existe um comprimento máximo da lista de argumentos para um novo processo no sistema POSIX. finddividirá a execução se os caminhos dos arquivos forem maiores que isso. Para ver o limite no Linux, use xargs --show-limits(não funcione no Mac OS, se alguém souber uma alternativa melhor, por favor comente aqui)

edit: roubado diretamente da resposta do Gnouc, a maneira POSIX de obter o comprimento máximo da lista de argumentos é getconf ARG_MAX. No entanto, realizei um experimento na minha máquina Mac OS, e parece que findusa um pouco mais da metade desse número. Isso é coerente com o fato de que, no sistema em que funciona, xargs --show-limitsnos diz que não usará o tamanho máximo do argumento (neste caso também usará cerca da metade desse número), no entanto, não consegui encontrar uma explicação por isso.

editar 2: parece que a única maneira confiável de determinar quantos parâmetros findserão mantidos juntos para cada invocação é experimentar, por exemplo, executando

find / -exec echo {} + | wc -cl

Como a saída de findpossui uma linha para cada echochamada, é possível contá-las usando wc -l. O número total de bytes echoed é a saída de wc -cvez. Ao dividir um pelo outro, você obtém o número médio de bytes nos parâmetros para cada chamada de comando (embora um valor ligeiramente mais baixo, devido ao arredondamento, aproximadamente a metade do comprimento médio de um caminho em seu sistema)

pqnet
fonte
xargsnão usa o tamanho máximo máximo do argumento, porque muitos programas precedem alguns argumentos adicionais e os transmitem a outros programas. Se xargspreencher os argumentos ao máximo absoluto, esses programas quebram, porque não haveria espaço para esses argumentos extras.
hvd 29/08
@hvd faz sentido. Mas então, existe uma maneira POSIX de saber quanto do buffer é usado por xargsou find?
Pqnet 29/08/14
Você pode executá-lo com uma lista muito longa de argumentos, determinando quantos argumentos foram passados ​​na primeira chamada (algo como yes . | xargs | head -n 1 | wc -c) e comparando-os à saída de getconf ARG_MAX. Mas, na verdade, experimentá-lo no meu sistema, percebo que a diferença é tão grande que parece que há mais do que estou ciente disso.
hvd 29/08
por isso se resume a experimentar ... Eu vou atualizar a minha resposta
pqnet