Existem muitos problemas com seus comandos.
Primeiro, locate *.c
só procura arquivos que correspondam *.c
se você executá-lo em um diretório que não contenha nenhum arquivo cujo nome corresponda a *.c
. Caso contrário, o shell expande *.c
para a lista de arquivos correspondentes. Isso provavelmente não está acontecendo, caso contrário, você obteria menos correspondências, mas deixar globs sem aspas como essa é um mau hábito, porque irá morder você um dia. (É um tópico frequente neste site.) O mesmo vale para find -name *.c
. Em vez disso, escreva
locate '*.c' …
find / -name '*.c' …
ou algo similar.
Existem alguns motivos pelos quais locate
e find
podem gerar resultados diferentes. Eles não parecem se aplicar no seu caso, já que você está recebendo o mesmo número de acessos, mas, mais uma vez, isso é algo que você precisa saber.
-
Os resultados de
locate
são armazenados em cache da última execução deupdatedb
. Isso geralmente é executado uma vez à noite.find
resultados calculados cada vez que você executar o comando. - Dependendo do sistema, em qual
locate
implementação você e como ela está configurada, ela pode permitir que você veja somente arquivos acessíveis publicamente (por exemplo, findutils GNU, em vez de mlocate ou slocate), ou pode fazer uma aproximação de os arquivos que você tem permissão para acessar (por exemplo, porque há uma configuração complexa envolvendo módulos de segurança do Linux que distinguem entre aplicativos que tentam acessar o arquivo). - O padrão
*SUFFIX
significa a mesma coisa paralocate
e parafind -name
(supondo queSUFFIX
não contenha barras ou curingas), mas outros padrões não. Por exemplo,locate foo
é equivalente afind / -name '*foo*'
, não afind / -name 'foo'
.
Outra coisa que pode, mas provavelmente não causa, problemas é que você canalizou mensagens de erro de find
para a parte de processamento de dados do seu comando. Você remove linhas contendo Permission denied
, o que faz com que você perca arquivos que contenham isso como parte de seu nome (ok, provavelmente você não possui nenhum) e faz com que qualquer mensagem de erro que não contenha Permission denied
seja interpretada como uma linha de entrada. Raramente é uma boa ideia misturar a saída de dados com a saída de erro, e é um absurdo aqui. Se você quiser ignorar os erros, redirecione-os para /dev/null
:
find … 2>/dev/null | …
O que definitivamente está mordendo você é que xargs
espera uma sintaxe de entrada diferente do que o find
produz. Na entrada de xargs
, qualquer espaço em branco separa itens, não apenas quebras de linha. Os três caracteres \'"
também são analisados especialmente. Espaços são comuns em nomes de arquivos e todos os outros caracteres são permitidos além de /
e de bytes nulos. Uma das linhas que xargs
recebe como entrada é
/usr/lib/python2.7/site-packages/setuptools/script template (dev).py
Para xargs
, são três itens: /usr/lib/python2.7/site-packages/setuptools/script
, template
e (dev).py
. O motivo das mensagens de erro de wc
agora deve estar claro.
Existem várias soluções para isso. Uma é usar o formato delimitado por nulo para find
e xargs
. Isso funciona com qualquer nome de arquivo, até mesmo nomes de arquivos contendo novas linhas (que são permitidas, mas incomuns).
find / -name '*.py' -print0 | xargs -0 wc -l | tail -3
Outra é esquecer a problemática xargs
e fazer find
invocar o comando diretamente.
find / -name '*.py' -exec wc -l {} + | tail -3
A primeira solução pode ser aplicável à sua implementação locate
, verifique se ela possui uma opção -0
. A segunda solução é específica para find
. Se você estiver preso à saída delimitada por nova linha de locate
e tiver a versão GNU de xargs
, poderá usar -d '\n'
para fazer com que ela analise a entrada como delimitada por nova linha sem qualquer forma de cotação. / p>
locate '*.py' | xargs -d '\n' wc -l | tail -3
Esse foi o seu principal problema. Um problema adicional é que há um comprimento máximo para a linha de comando. O comando xargs
(ou a ação -exec … {} +
de find
) coloca quantos nomes de arquivo puder em uma linha de comando, e se eles não couberem todos, então o comando (aqui, wc -l
) é executado várias vezes, uma vez para cada lote de arquivos. Com tail -3
, você só verá os dois últimos arquivos e o total do último lote (supondo que haja pelo menos dois arquivos no último lote). Os arquivos nos lotes anteriores não são refletidos nessa saída. Como find
e locate
podem não relatar arquivos na mesma ordem, você pode ver resultados diferentes.
Como resolver o problema de tamanho máximo depende do que você deseja fazer com os dados. Se tudo o que você quer é o total geral, então uma maneira (assumindo que não há novas linhas nos nomes dos arquivos) é contar todas as linhas total
.
… | xargs -d '\n' wc -l | awk '/^[0-9]+\ttotal$/ {total += $1} END {print total}'