La salida de tubería de 'find' a 'xargs wc' da totales irrazonables

La salida de tubería de 'find' a 'xargs wc' da totales irrazonables

En un proyecto con miles de archivos, quería comparar el total de líneas de código con líneas de código solo en PHP (descartando CSS, JavaScript, etc.).

cuando corro

find . -type f | xargs wc -l

el total en la última línea esmás bajoque cuando corro

find -E . -regex '.+\.(php|inc)' -type f | xargs wc -l

Teniendo en cuenta que el segundo findtiene que ser una lista de archivos más pequeña que (es un subconjunto estricto de) el primero find, ¿cómo podría wcinformar un total más alto en el segundo caso?

Respuesta1

xargssólo puede pasar ARG_MAXbytes de argumentos para wc.

En mi Mac, ARG_MAX es más pequeño que los nombres completos de los archivos y las rutas relativas de todos los archivos del proyecto, por lo que en elprimerocomando, xargsarrojó los resultados del findawc en dos lotes, lo que significaba que wcse apagódos totales, rodeado de miles de nombres de archivos. Pero resultó que ARG_MAX era más grande que elsegundo findsalida, por lo que el segundo hallazgo más pequeño se muestra enuno wctotal.

La solución fue usar estos comandos, para poder ver todos los totales sin las (aburridas) líneas de recuento de archivos individuales:

find . -type f | xargs wc -l | grep total
find -E . -regex '.+\.(php|inc)' -type f | xargs wc -l | grep total

Luego sume las varias filas "totales" a mano.

Respuesta2

Hay muchas maneras de hacer esto y xargsno es la mejor. Aquí hay un par:

  1. La más sencilla, es pasar por catcada uno de los archivos encontrados findy contar las líneas. Cuidado, esto solo funciona si los nombres de tus archivos no tienen espacios ni caracteres extraños:

    find . -type f | while read n; do cat $n; done | wc -l
    find -E . -regex '.+\.(php|inc)' -type f | while read n; do cat $n; done | wc -l 
    

    Si es probable que los nombres de sus archivos contengan caracteres extraños (barras, espacios, etc.), utilice esto en su lugar:

    find . -type f | while IFS= read -r n; do cat $n; done | wc -l
    find -E . -regex '.+\.(php|inc)' -type f | while IFS= read -r n; do cat $n; done | wc -l 
    
  2. Una mejor manera es usar -execla opción de buscar:

    find . -name "*.pep" -exec cat {} \; | wc
    find -E . -regex '.+\.(php|inc)' -type f -exec cat {} \; | wc
    

Respuesta3

¡Úselo awkpara resumir los diversos números "totales" de las wc -lsalidas!

(Nota: wc -ldevuelve el número de caracteres de nueva línea, es decir, las "líneas" finales sin un \ncarácter final no se contarán, como es el caso de awko sed.)

export LC_ALL=C
find . -type f -print0 | xargs -0 wc -l | 
    awk '/^ *[[:digit:]]+ total$/{ total+=$1 }END{print total}'


# xargs alternatives using: find ... -exec <wc|awk|sed> ... '{}' +
#man find | less -p '{} \+'

# wc
find . -type f -exec wc -l '{}' + 2>/dev/null | 
   awk '/^ *[[:digit:]]+ total$/{ total+=$1 }END{print total}'

# awk
find . -type f -exec awk 'END {print NR}' '{}' + 2>/dev/null | 
    awk '{ total+=$1 }END{print total}'

# sed
find . -type f -exec sed -n '$=' '{}' + 2>/dev/null | 
    awk '{ total+=$1 }END{print total}'

información relacionada