A saída de tubulação de 'find' para 'xargs wc' fornece totais irracionais

A saída de tubulação de 'find' para 'xargs wc' fornece totais irracionais

Em um projeto com milhares de arquivos, eu queria comparar o total de linhas de código com linhas de código apenas em PHP (descartando CSS, JavaScript, etc.).

Quando eu corro

find . -type f | xargs wc -l

o total na última linha émais baixodo que quando eu corro

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

Considerando que o segundo finddeve ser uma lista menor de arquivos do que (é um subconjunto estrito) do primeiro find, como poderia wcrelatar um total maior no segundo caso?

Responder1

xargssó pode passar ARG_MAXbytes de argumentos para wc.

No meu Mac, ARG_MAX é menor que os nomes completos dos arquivos e os caminhos relativos dos arquivos de todo o projeto, portanto, noprimeirocomando, xargsdespejou os resultados do findtowc em dois lotes, o que significava que wccolocar para foradois totais, cercado por milhares de nomes de arquivos. Mas ARG_MAX era maior que osegundo findsaída, então o segundo achado menor é mostrado emum wctotal.

A solução foi usar estes comandos, para que eu pudesse ver todos os totais sem as (chatas) linhas de contagem de arquivos individuais:

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

Em seguida, some as várias linhas do "total" manualmente.

Responder2

Há muitas maneiras de fazer isso e xargsnão é a melhor. Aqui estão alguns:

  1. O mais simples é catcada um dos arquivos encontrados finde contar as linhas. Cuidado, isso só funciona se os nomes dos seus arquivos não tiverem espaços ou caracteres estranhos:

    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 
    

    Se for provável que os nomes dos seus arquivos contenham caracteres estranhos (barras, espaços, etc.), use isto:

    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. A melhor maneira é usar -execa opção find:

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

Responder3

Use awkpara somar os vários números "totais" das wc -lsaídas!

(Nota: wc -lretorna o número de caracteres de nova linha, ou seja, "linhas" finais sem um \ncaractere final não serão contadas - como é o caso de awkou 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}'

informação relacionada