O que é caro, é fazer chamadas do sistema nos arquivos (para as chamadas do sistema e para a E / S).
As coisas como -type
, -mtime
requerem uma chamada de sistema lstat(2)
no arquivo. -name
, -path
, -regex
não (embora, é claro, ele tenha feito chamadas do sistema para os diretórios que eles contêm para ler seu conteúdo).
Geralmente, find
faz um lstat()
de qualquer maneira (porque precisa saber se um arquivo é um diretório ou não descer nele, a menos que essa informação seja fornecida no readdir()
), mas há casos em que pode fazer sem isto. Por exemplo, se o número de links de um diretório for menor que 3, em alguns sistemas de arquivos, find
saberá que ele não tem subdiretórios e que algumas implementações find
otimizarão ao não fazer lstat
s nele.
-xtype
fará com que stat(2)
, -printf ...
, -ls
possa causar stat()
, lstat()
, readlink()
, -lname
a lstat()
e readlink()
.
É por isso que você pode colocar o -name
/ -path
/ -regex
... primeiro. Se eles puderem descartar um arquivo, eles poderão evitar um ou mais syscalls.
Agora, um -regex
pode ser mais caro que um -name
, mas não tenho certeza se você conseguiria muito trocando-os.
Observe também que algumas implementações de find
como o GNU find
reordenam as verificações por padrão quando possível. Veja:
info find 'Optimisation Options'
em um sistema GNU ( lá no gnu.org para a versão mais recente do GNU findutils
).
Normalmente, se você fez seus testes em um sistema GNU, os dois comandos farão a mesma coisa porque find
teria movido o -name
para a frente de qualquer maneira.
Portanto, para que -type d -name ...
vs -name ... -type d
faça a diferença, você precisa de uma implementação de find
que não otimize reordenando esses predicados e que faça alguma otimização por não fazer um lstat()
em cada arquivo.
Onde haverá uma diferença (enorme), independentemente da implementação estar em:
find . -name 'x*' -exec test -d {} \; -print
vs:
find . -exec test -d {} \; -name 'x*' -print
find
não pode reordenar o -exec
, pois isso pode introduzir diferenças funcionais ( find
não pode saber se o comando que é executado é apenas para testes ou faz outra coisa).
E é claro que -exec ... {} \;
é várias ordens de magnitude mais caro do que qualquer outro predicado, pois significa "bifurcar" um processo e executar um comando nele (e executar muitas chamadas do sistema) e aguardar pelo código de saída.
$ time find /usr/lib -exec test -d {} \; -name z\* -print > /dev/null
1.03s user 12.52s system 21% cpu 1:03.43 total
$ time find /usr/lib -name z\* -exec test -d {} \; -print > /dev/null
0.09s user 0.14s system 62% cpu 0.367 total
(o primeiro chama test
para cada arquivo em /usr/lib
(56685), o segundo apenas nos arquivos cujo nome começa com z
(147)).
Observe que -exec test -d {} \;
não é o mesmo que -type d
. É o equivalente portátil do -xtype d
específico do GNU.