Como obtenho um único total de linhas com 'wc -l'?

10

Eu adicionei um alias do git para fornecer as contagens de linha de arquivos específicos no meu histórico:

[alias]
lines = !lc() { git ls-files -z ${1} | xargs -0 wc -l; }; lc

No entanto, wc -l está relatando vários totais, de modo que, se eu tiver mais de ~ 100 mil linhas, ele informará o total para eles e, em seguida, seguirá em frente. Aqui está um exemplo:

< 100k linhas (saída desejada)

$ git lines \*.xslt
  46 packages/NUnit-2.5.10.11092/doc/files/Summary.xslt
 232 packages/NUnit-2.5.10.11092/samples/csharp/_UpgradeReport_Files/UpgradeReport.xslt
 278 total

> 100k linhas (teve que passar por grep "total" )

$ git lines \*.cs | grep "total"
 123569 total
 107700 total
 134796 total
 111411 total
  44600 total

Como obtenho um total verdadeiro de wc -l , não uma série de subtotais?

    
por Ehryk 31.01.2014 / 20:46

4 respostas

10

Tente isso e peça desculpas por ser óbvio:

cat *.cs | wc -l

ou, com git:

git ls-files -z ${1} | xargs -0 cat | wc -l

Se você realmente deseja que a saída pareça com wc output, com contagens individuais e uma soma, você pode usar awk para adicionar as linhas individuais:

git ls-files -z ${1} | xargs -0 wc -l |
awk '/^[[:space:]]*[[:digit:]]+[[:space:]]+total$/{next}
     {total+=$1;print}
     END {print total,"total"}'

Isso não será tão bom quanto wc , caso isso seja importante para você. Para fazer isso, você precisaria ler a entrada inteira e salvá-la, calculando o total e, em seguida, usar o total para calcular a largura do campo antes de usar essa largura de campo para imprimir uma saída formatada das linhas lembradas. Como projetos de renovação em casa, os scripts awk nunca são realmente concluídos.

(Nota aos editores entusiastas: a expressão regular na primeira condição awk é caso haja um arquivo cujo nome comece com "total" e um espaço; caso contrário, a condição poderia ter sido muito mais simples. $2 == "total" .)

    
por 31.01.2014 / 21:35
7

Se você estiver executando o Linux, seu wc provavelmente vem do GNU Coreutils e tem uma opção --files0-from para ler um arquivo (ou stdin) contendo uma lista arbitrariamente longa de nomes de arquivo terminados em NUL para contar. A documentação GNU Coreutils wc diz "Isto é útil quando a lista de nomes de arquivos é tão longo que pode exceder uma limitação de comprimento de linha de comando. Nesses casos, executar wc via xargs é indesejável porque divide a lista em partes e faz com que wc imprima um total para cada sublist em vez da lista inteira. "

Então tente isto:

lc() { git ls-files -z ${1} | wc -l --files0-from=- ; } 

Editar: Como seu wc é do último milênio e não tem essa opção, aqui está uma solução mais portátil, supondo que você tenha awk e não tenha nenhum arquivo chamado "total". Ele filtrará a saída de wc , omitindo qualquer total linhas e, em vez disso, resumindo-as e imprimindo o total geral no final.

Uma coisa que não sei é se a implementação% al_de% alias terá problemas com git e $1 entre aspas simples, que precisam ser passadas inalteradas para $2 .

lc() {
  git ls-files -z ${1} |
  xargs -0 wc -l |
  awk 'BEGIN { total=0; } { if (NF==2 && $2 == "total") total += $1; else print; } END { print total, "total"; }' ;
}
    
por 31.01.2014 / 22:40
4

O problema é xargs , que está dividindo o comando em várias execuções, portanto, wc está relatando o total para cada vez. Você tem algumas opções, pode manter as coisas como estão e analisar a wc output:

git ls-files -z ${1} | xargs -0 wc -l | awk '/total/{k+=$1}END{print k,"total"}';

Você pode catar os arquivos:

git ls-files -z ${1} | xargs -0 cat | wc -l

Ou você pode ignorar xargs no total (adaptado de aqui ):

unset files i; while IFS= read -r -d $'
git ls-files -z ${1} | xargs -0 wc -l | awk '/total/{k+=$1}END{print k,"total"}';
' name; do files[i++]="$name"; done < <(git ls-files -z ${1} ) && wc -l "${files[@]}"

Isso será cancelado se sua lista de arquivos for maior que ARG_MAX .

    
por 31.01.2014 / 21:57
-1
j=0; for i in *.php *.js *.css; do let j+='wc -l $i | awk {'print $1'}'; done; echo $j;
    
por 31.01.2014 / 21:35

Tags