Al contar los files fuente y LOC con Buscar y encontrar, ¿por qué los files Python son diferentes?

Tengo problemas para entender por qué find y locate funcionaría de manera diferente para los files fuente C y Python. Mi objective es contar los files fuente numéricos y la sum de sus líneas de código fuente para un idioma determinado. Usé find y locate para comparar resultados ( updatedb acaba de ejecutarse antes de esto con sudo para asegurarme de que locate los resultados actuales de los informes).

Para files C esto funciona como se espera, la cantidad de files fuente es la misma

 $ find / -name *.c |& grep -v "Permission denied" | wc -l 1056 $ locate *.c | wc -l 1056 

Usando xargs , la sum de las líneas de código fuente también aparece de la misma manera.

 $ locate *.c | xargs wc -l | tail -3 138 /usr/src/kernels/3.10.0-693.el7.ppc64/scripts/selinux/genheaders/genheaders.c 147 /usr/src/kernels/3.10.0-693.el7.ppc64/scripts/selinux/mdp/mdp.c 705376 total $ find / -name *.c |& grep -v "Permission denied" | xargs wc -l | tail -3 2994 /opt/Python-3.6.2/Objects/listobject.c 821 /opt/Python-3.6.2/Objects/bytes_methods.c 705376 total 

Solo para probar, esto también funciona para files con extensión .java . Obtengo los mismos resultados consistentes. Sin embargo, cuando repito lo mismo con los files de Python (es decir, la extensión .py )

El número de file de origen coincide.

 $ find / -name *.py |& grep -v "Permission denied" | wc -l 9249 $ locate *.py | wc -l 9249 

Pero la sum de líneas de código para files Python da resultados muy diferentes.

 $ locate *.py | xargs wc -l | tail -3 wc: /usr/lib/python2.7/site-packages/setuptools/script: No such file or directory wc: template: No such file or directory wc: (dev).py: No such file or directory wc: /usr/lib/python2.7/site-packages/setuptools/script: No such file or directory wc: template.py: No such file or directory 220 /usr/src/kernels/3.10.0-693.el7.ppc64/scripts/rt-tester/rt-tester.py 129 /usr/src/kernels/3.10.0-693.el7.ppc64/scripts/tracing/draw_functrace.py 753350 total $ find / -name *.py |& grep -v "Permission denied" | xargs wc -l | tail -3 wc: /usr/lib/python2.7/site-packages/setuptools/script: No such file or directory wc: template: No such file or directory wc: (dev).py: No such file or directory wc: /usr/lib/python2.7/site-packages/setuptools/script: No such file or directory wc: template.py: No such file or directory 1919 /opt/Python-3.6.2/python-gdb.py 69 /opt/Python-3.6.2/python-config.py 1034101 total 

¿Alguien puede explicar por qué este es el caso? Lo que es tan diferente de los files de Python (realmente no puedo creer que tenga que ver con el tipo de file, pero estoy perplejo). ¿Que me estoy perdiendo aqui?

Los mismos resultados impares bajo Ubuntu y RH

updatedb con sudo , pero estoy ejecutando todos estos commands como un usuario normal.

Hay muchos problemas con tus commands.

Primero, locate *.c solo busca los files que coincidan con *.c si lo ejecuta en un directory que no contiene ningún file cuyo nombre coincida con *.c . De lo contrario, el shell expande *.c a la list de files coincidentes. Probablemente eso no ocurra, de lo contrario obtendrías muchas less coincidencias, pero dejar los globos sin comillas como este es un mal hábito porque te morderá algún día. (Es un tema frecuente en este sitio.) Lo mismo ocurre con find -name *.c . En cambio, escribe

 locate '*.c' … find / -name '*.c' … 

o algo similar.

Hay algunos puntos comunes por los cuales locate y find pueden dar resultados diferentes. No parecen aplicarse en su caso, ya que obtiene el mismo número de visitas, pero una vez más, esto es algo que debe tener en count.

  • locate resultados de locate se almacenan en caching desde la última ejecución de updatedb . Esto generalmente se ejecuta una vez por la noche. find resultados calculados cada vez que ejecutas el command.
  • Dependiendo del sistema, en qué locate implementación y cómo está configurada, puede permitirte ver solo files de acceso público (p. Ej., Findutils de GNU, en lugar de mlocate o slocate), o puede hacer una aproximación de los files que tú ' Se permite el acceso (por ejemplo, porque hay una configuration compleja que involucra modules de security de Linux que distinguen entre las aplicaciones que intentan acceder al file).
  • El patrón *SUFFIX significa lo mismo para locate y find -name (suponiendo que SUFFIX no contiene barras o comodines), pero otros patrones no lo hacen. Por ejemplo, locate foo es equivalente a find / -name '*foo*' , no a find / -name 'foo' .

Otra cosa que podría causar problemas, aunque probablemente no, es que haya enviado posts de error desde la parte de procesamiento de datos de su command. Quita las líneas que contienen Permission denied , lo que hace que pierda files que lo contengan como parte de su nombre (vale, probablemente no tenga ninguno) y hace que cualquier post de error que no contenga Permission denied sea ​​interpretado como un línea de input. Raramente es una buena idea mezclar datos de salida con salida de error, y es absurdo aquí. Si desea ignorar errores, networkingirigirlos a /dev/null :

 find … 2>/dev/null | … 

Lo que definitivamente te está mordiendo es que xargs espera una syntax de input que sea diferente de lo que produce el find . En la input de xargs , cualquier espacio en blanco separa elementos, no solo saltos de línea. Los tres caracteres \'" también se analizan especialmente. Los espacios son comunes en los nombres de file y todos los demás caracteres están permitidos aparte de / y de los bytes nulos. Una de las líneas que xargs recibe como input es

 /usr/lib/python2.7/site-packages/setuptools/script template (dev).py 

Para xargs , eso son tres elementos: /usr/lib/python2.7/site-packages/setuptools/script , template y (dev).py . El motivo de los posts de error del wc ahora debería ser claro.

Hay varias soluciones para esto. Una es usar el formatting delimitado por nulos para find y xargs . Esto funciona con cualquier nombre de file, incluso los nombres de file que contienen líneas nuevas (que están permitidas, pero poco comunes).

 find / -name '*.py' -print0 | xargs -0 wc -l | tail -3 

Otra es olvidarse de los xargs problemáticos y hacer que find invoque directamente el command.

 find / -name '*.py' -exec wc -l {} + | tail -3 

La primera solución puede ser aplicable a su implementación de locate , verifique si tiene una opción -0 . La segunda solución es específica para find . Si está atascado con salida delimitada por nueva línea desde locate , y tiene la versión GNU de xargs , puede usar -d '\n' para hacer que analice la input como delimitada por nueva línea sin ninguna forma de comillas.

 locate '*.py' | xargs -d '\n' wc -l | tail -3 

Este fue tu problema principal. Un problema adicional es que hay una longitud máxima para la línea de command. El command -exec … {} + (o el -exec … {} + acción de find ) pone tantos nombres de file como puede en una línea de command, y si no todos encajan, entonces se ejecuta el command (aquí, wc -l ) varias veces, una vez por cada lote de files. Con tail -3 , solo verá los dos últimos files y el total del último lote (suponiendo que haya al less dos files en el último lote). Los files en los lotes anteriores no se reflejan en esta salida. Dado que find y locate no puede informar files en el mismo order, puede ver resultados diferentes.

La forma de resolver el problema de longitud máxima depende de lo que quiera hacer con los datos. Si todo lo que quiere son totales generales, entonces una forma (suponiendo que no haya nuevas líneas en los nombres de los files) es contar todas las líneas total .

 … | xargs -d '\n' wc -l | awk '/^[0-9]+\ttotal$/ {total += $1} END {print total}'