Como contar todas as linhas de código em um diretório recursivamente?


1625

Temos um aplicativo PHP e queremos contar todas as linhas de código em um diretório específico e seus subdiretórios. Não precisamos ignorar comentários, pois estamos apenas tentando ter uma idéia aproximada.

wc -l *.php 

Esse comando funciona muito bem em um determinado diretório, mas ignora os subdiretórios. Eu estava pensando que isso poderia funcionar, mas está retornando 74, o que definitivamente não é o caso ...

find . -name '*.php' | wc -l

Qual é a sintaxe correta para alimentar todos os arquivos?

Respostas:


2650

Tentar:

find . -name '*.php' | xargs wc -l

A ferramenta SLOCCount pode ajudar.

Ele fornecerá uma contagem precisa de linhas de código fonte para qualquer hierarquia que você apontar, além de algumas estatísticas adicionais.

Saída classificada:

find . -name '*.php' | xargs wc -l | sort -nr


31
cloc.sourceforge.net pode valer a pena olhar como uma alternativa para sloccount (mais idiomas, mas menos informações)
Aster

31
com arquivos include também:find . -name '*.php' -o -name '*.inc' | xargs wc -l
rymo

52
Isso imprimirá mais de um número quando houver muitos arquivos (porque wcserá executado várias vezes. Também não lida com muitos nomes de arquivos especiais.
#

42
@idober:find . -name "*.php" -not -path "./tests*" | xargs wc -l
endre 19/10/2013

19
Se um nome de diretório contiver algum espaço ... o comando acima falhará !!
precisa saber é o seguinte

474

Para outro one-liner:

( find ./ -name '*.php' -print0 | xargs -0 cat ) | wc -l

funciona em nomes com espaços, gera apenas um número.


1
+1 no mesmo nome ... pesquisado para sempre ... todos os outros comandos "find" retornaram apenas o número de arquivos reais ... o material -print0 aqui obteve a contagem de linhas real para mim !!! obrigado!
Ronedog

3
@ TorbenGundtofte-Bruun - ver man find.. print0 com xargs -0 permite operar em arquivos que têm espaços ou outros caracteres estranhos em seu nome
Shizzmo

2
@ TorbenGundtofte-Bruun - também, o -0 em xargs corresponde ao print0, é um tipo de codificação / decodificação para lidar com os espaços.
Tristan Reid

7
Se você precisar de mais de um filtro de nome, descobri que (pelo menos na versão MSYSGit do find), você precisa de ( find . \( -name '*.h' -o -name '*.cpp' \) -print0 | xargs -0 cat ) | wc -l
parênteses

1
@DesignbyAdrian: O registro no diário ajuda na recuperação de falhas, não na velocidade. É provável que você esteja tendo um bom desempenho devido ao armazenamento em cache ou a um HDD muito rápido.
jmh

398

Se estiver usando uma versão decentemente recente do Bash (ou ZSH), é muito mais simples:

wc -l **/*.php

No shell Bash, isso requer que a globstaropção seja definida, caso contrário, o **operador glob não é recursivo. Para habilitar essa configuração, emita

shopt -s globstar

Para tornar isso permanente, adicione-o a um dos arquivos de inicialização ( ~/.bashrc, ~/.bash_profileetc.).


7
Estou votando nisso por simplicidade, no entanto, só quero ressaltar que ele não parece pesquisar os diretórios recursivamente, apenas verifica os subdiretórios do diretório atual. Isso está no SL6.3.
Godric Seer

7
Isso depende do seu shell e das opções que você definiu. É necessário globstardefinir o Bash para que isso funcione.
Michael selvagem

2
@PeterSenna, com o atual arquivo do kernel 3.9.8, o comando wc -l **/*.[ch]encontra um total de 15195373 linhas. Não tenho certeza se você considera isso um "valor muito baixo". Novamente, você precisa ter certeza de ter globstarativado o Bash. Você pode verificar com shopt globstar. Para habilitá-lo explicitamente, faça shopt -s globstar.
Michael Wild

5
@MichaelWild Esta é uma boa solução, mas ainda será excedida ARG_MAXse você tiver um grande número de .phparquivos, pois wcnão está embutido.
Reinstate Monica Please

1
@AlbertSamuel Não, você precisaria comparar a lista de arquivos produzidos pelos dois métodos. Meu método tem o problema de não funcionar para um grande número de arquivos, conforme mencionado por @BroSlow. A resposta aceita falhará se os caminhos produzidos por findcontiverem espaços. Isso pode ser corrigido usando print0e --nullcom as chamadas finde xargs, respectivamente.
Michael Wild

363

Você pode usar o cloc utilitário criado para esse fim exato. Ele informa cada quantidade de linhas em cada idioma, juntamente com quantas delas são comentários, etc. O CLOC está disponível no Linux, Mac e Windows.

Exemplo de uso e saída:

$ cloc --exclude-lang=DTD,Lua,make,Python .
    2570 text files.
    2200 unique files.                                          
    8654 files ignored.

http://cloc.sourceforge.net v 1.53  T=8.0 s (202.4 files/s, 99198.6 lines/s)
-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
Javascript                    1506          77848         212000         366495
CSS                             56           9671          20147          87695
HTML                            51           1409            151           7480
XML                              6           3088           1383           6222
-------------------------------------------------------------------------------
SUM:                          1619          92016         233681         467892
-------------------------------------------------------------------------------

4
Essa é uma ferramenta adorável que roda de maneira agradável e rapidamente, fornecendo estatísticas úteis no final. Adoro.
Rob Forrest

4
Observe que você pode executar comandos Unix no Windows usando o cygwin (ou outras portas / ambientes similares). Para mim, ter esse tipo de acesso tão extremamente útil, é uma necessidade. Uma linha de comando unix é mágica. Eu gosto especialmente de expressões regulares e perl.
Curtis Yallop

O CLOC e o SLOCCount funcionam bem no macbook de meados de 2015. Observe que seus números são próximos, mas não exatamente iguais, para o projeto Java Android de 127k. Observe também que o equivalente do iOS tinha 2x o LoC; por isso, o "custo" métrica em SLOCCount pode ser desligado (ou talvez iOS dev make 2x o Android dev make :-).
maxweber

2
Você consideraria editar o início desta pergunta para deixar claro que clocé multiplataforma, já que é apenas um script Perl?
Kyle Strand

Simplesmente perfeito, também funciona bem no Windows bash.
Yurisnm 15/04/19

100

Em sistemas do tipo UNIX, existe uma ferramenta chamada clocque fornece estatísticas de código.

Corri em um diretório aleatório em nossa base de código que diz:

      59 text files.
      56 unique files.                              
       5 files ignored.

http://cloc.sourceforge.net v 1.53  T=0.5 s (108.0 files/s, 50180.0 lines/s)
-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
C                               36           3060           1431          16359
C/C++ Header                    16            689            393           3032
make                             1             17              9             54
Teamcenter def                   1             10              0             36
-------------------------------------------------------------------------------
SUM:                            54           3776           1833          19481
-------------------------------------------------------------------------------

2
O @moose tecnicamente simtao o mencionou especificamente como uma solução para usuários do Windows, sem mencionar o Linux ou o Unix.
Tim Seguine

5
@moose Table foi editado em sua resposta muito mais tarde do que a minha resposta, agora os dois realmente se parecem.
Calmarius

Eu gosto disso. cloc é realmente legal. Mas o que significa esse nome?
Manoel Vilela

Também está no Windows agora! Supondo que você tem achocolatada :choco install cloc
icc97

35

Você não especificou quantos arquivos existem ou qual é a saída desejada. É isso que você está procurando:

find . -name '*.php' | xargs wc -l

2
Isso funcionará, desde que não haja muitos arquivos: se houver muitos arquivos, você obterá várias linhas como resultado (o xargs dividirá a lista de arquivos em várias sub-listas)
Pascal MARTIN

Ah sim. Por isso eu disse que Ele não especificou quantos arquivos existem. Minha versão é mais fácil de lembrar, mas a versão de Shin é melhor se você tiver mais do que alguns arquivos. Estou votando.
Paweł Polewicz 18/03/10

Eu precisava adaptar este para uso em uma função, onde aspas simples são muito restritivas: go () { mkdir /tmp/go; [[ -f ./"$1" ]] && mv ./"$1" /tmp/go; (find ./ -type f -name "$*" -print0 | xargs -0 cat ) | wc -l; wc -l /tmp/go/*; mv /tmp/go/* . } Os resultados foram perto de slocount para *.py, mas não sabia *.js, *.html.
jalanb

31

Ainda outra variação :)

$ find . -name '*.php' | xargs cat | wc -l

Edit: isso dará a soma total, em vez de arquivo por arquivo.

Edit2: Adicione .depois findpara fazê-lo funcionar


ambas as respostas somam as linhas.
josh123a123

Pelo menos em cygwin, obtive melhores resultados com:$ find -name \*\.php -print0 | xargs -0 cat | wc -l
Martin Haeberli 12/12

em Darwin, isso fornece apenas um total geral: find . -name '*.php' | xargs cat | wc -l... enquanto que isso fornece um arquivo por arquivo e um total geral:find . -name '*.php' | xargs wc -l
OsamaBinLogin 19/16/16

30

Surpreendentemente, não há resposta baseada em encontrar -exece awk. Aqui vamos nós:

find . -type f -exec wc -l {} \; | awk '{ SUM += $0} END { print SUM }'

Este trecho encontra para todos os arquivos ( -type f). Para localizar por extensão de arquivo, use -name:

find . -name '*.py' -exec wc -l '{}' \; | awk '{ SUM += $0; } END { print SUM; }'

2
Funcionalmente, isso funciona perfeitamente, mas em uma lista grande (fonte linux) é realmente lento porque está iniciando um processo wc para cada arquivo, em vez de um processo wc para todos os arquivos. Eu cronometrei em 31 segundos usando esse método em comparação com 1,5 segundos usando find . -name '*.c' -print0 |xargs -0 wc -l. Dito isto, esse método mais rápido (pelo menos no OS X) acaba imprimindo "total" várias vezes, portanto é necessária uma filtragem adicional para obter um total adequado (eu postei detalhes na minha resposta).
Doug Richardson

Isso tem o benefício de trabalhar para um número ilimitado de arquivos. Bem feito!
ekscrypto

1
esta é uma solução muito melhor depois de trabalhar com grande quantidade de GB e arquivos. fazer um wcna forma de a caté lento porque o sistema deve primeiro processar todos os GB para começar a contar as linhas (testado com 200 GB de jsons, arquivos de 12k). fazendo wcprimeiro e depois contar o resultado é muito mais rápido
ulkas

1
@DougRichardson, você pode considerar isso: find . -type f -exec wc -l {} \+ou find . -name '*.py' -type f -exec wc -l {} \+ que imprime um total no final da saída. Se tudo o que lhe interessa é o total, você pode ir um pouco mais além e usar tail: find . -type f -exec wc -l {} \+ | tail -1ou #find . -name '*.py' -type f -exec wc -l {} \+ | tail -1
JamieJag

25

Mais comum e simples quanto a mim, suponha que você precise contar arquivos de diferentes extensões de nome (digamos, também nativos)

wc $(find . -type f | egrep "\.(h|c|cpp|php|cc)" )

Obrigado pelo feedback, eu o corrigi.


6
isso não faz exatamente o que você pensa. encontrar . -name ' . [am]' é idêntico a encontrar. -name ' . [a | m]' ambos encontrarão todos os arquivos que terminam com .m ou .a
Omry Yadan

1
mas o segundo também encontrará arquivos que terminam em. , caso existam. Então [h | c | cpp | php | cc] acaba sendo o mesmo que [hcp |].
OsamaBinLogin 19/03/19

backticks estão obsoletos, prefere #$()
Sandburg

Isso funciona com o Cygwin. Obviamente, a unidade "C: \" deve seguir a convenção cygwin, como por exemplo: wc $ (find / cygdrive / c // SomeWindowsFolderj / -type f | egrep "\. (H | c | cpp | php | cc) ")
Christian Gingras

21

POSIX

Diferentemente da maioria das outras respostas aqui, elas funcionam em qualquer sistema POSIX, para qualquer número de arquivos e com qualquer nome de arquivo (exceto onde indicado).


Linhas em cada arquivo:

find . -name '*.php' -type f -exec wc -l {} \;
# faster, but includes total at end if there are multiple files
find . -name '*.php' -type f -exec wc -l {} +

Linhas em cada arquivo, classificadas pelo caminho do arquivo

find . -name '*.php' -type f | sort | xargs -L1 wc -l
# for files with spaces or newlines, use the non-standard sort -z
find . -name '*.php' -type f -print0 | sort -z | xargs -0 -L1 wc -l

Linhas em cada arquivo, classificadas por número de linhas, decrescente

find . -name '*.php' -type f -exec wc -l {} \; | sort -nr
# faster, but includes total at end if there are multiple files
find . -name '*.php' -type f -exec wc -l {} + | sort -nr

Total de linhas em todos os arquivos

find . -name '*.php' -type f -exec cat {} + | wc -l

19

Existe uma pequena ferramenta chamada sloccount para contar as linhas de código no diretório Deve-se notar que ele faz mais do que você deseja, pois ignora linhas / comentários vazios, agrupa os resultados por linguagem de programação e calcula algumas estatísticas.


Para Windows, LocMetrics fazer o trabalho
Camille

15

O que você quer é um forloop simples :

total_count=0
for file in $(find . -name *.php -print)
do
    count=$(wc -l $file)
    let total_count+=count
done
echo "$total_count"

3
esse exagero não é comparado às respostas que sugerem xargs?
197 Nathan Fellman

5
Não, Nathan. As respostas xargs não necessariamente imprimem a contagem como um único número. Pode apenas imprimir um monte de subtotais.
Rob Kennedy

3
o que esse programa fará se os nomes dos arquivos contiverem espaços? E as novas linhas? ;-)
Paweł Polewicz

38
Se seus nomes de arquivos contiverem novas linhas, eu diria que você tem problemas maiores.
Kzqai 31/08/2012

2
@ennuikiller Número de problemas com isso, antes de tudo, ele será quebrado em arquivos com espaços em branco. A configuração IFS=$'\n'antes do loop o corrigia pelo menos para todos os arquivos, exceto as novas linhas em seus nomes. Segundo, você não está citando '*.php', então ele será expandido pelo shell e não find, e o ergo não encontrará nenhum arquivo php nos subdiretórios. Também -printé redundante, pois está implícito na ausência de outras ações.
Reinstate Monica Please

12

apenas para fontes:

wc `find`

para filtrar, basta usar grep

wc `find | grep .php$`

11

Um simples que será rápido, usará todo o poder de pesquisa / filtragem de find, não falhará quando houver muitos arquivos (excesso de argumentos numéricos), funcionará bem com arquivos com símbolos engraçados em seu nome, sem usar xargs, não iniciará um número inutilmente alto de comandos externos (graças a +for find's -exec). Aqui está:

find . -name '*.php' -type f -exec cat -- {} + | wc -l

2
Eu estava prestes a postar uma variante disso (em \;vez de +não estar ciente disso), essa resposta deveria ser a resposta correta.
Mark K Cowan

7

Eu sei que a pergunta está marcada como , mas parece que o problema que você está tentando resolver também está relacionado ao PHP.

Sebastian Bergmann escreveu uma ferramenta chamada PHPLOC que faz o que você deseja e, além disso, fornece uma visão geral da complexidade de um projeto. Este é um exemplo de seu relatório:

Size
  Lines of Code (LOC)                            29047
  Comment Lines of Code (CLOC)                   14022 (48.27%)
  Non-Comment Lines of Code (NCLOC)              15025 (51.73%)
  Logical Lines of Code (LLOC)                    3484 (11.99%)
    Classes                                       3314 (95.12%)
      Average Class Length                          29
      Average Method Length                          4
    Functions                                      153 (4.39%)
      Average Function Length                        1
    Not in classes or functions                     17 (0.49%)

Complexity
  Cyclomatic Complexity / LLOC                    0.51
  Cyclomatic Complexity / Number of Methods       3.37

Como você pode ver, as informações fornecidas são muito mais úteis da perspectiva de um desenvolvedor, porque podem dizer a grosso modo como um projeto é complexo antes de começar a trabalhar com ele.


7

Acho que ninguém nunca verá isso enterrado na parte de trás ... No entanto, nenhuma das respostas até agora aborda o problema de nomes de arquivos com espaços. Além disso, todo esse uso xargsestá sujeito a falha se o comprimento total dos caminhos na árvore exceder o limite de tamanho do ambiente de shell (o padrão é alguns megabytes no Linux). Aqui está um que resolve esses problemas de maneira bastante direta. O subshell cuida de arquivos com espaços. oawk total do fluxo de wcsaídas de arquivos individuais , portanto, nunca deve ficar sem espaço. Também restringe execapenas os arquivos (pulando diretórios):

find . -type f -name '*.php' -exec bash -c 'wc -l "$0"' {} \; | awk '{s+=$1} END {print s}' 

6

WC -L? use melhor o GREP -C ^

wc -l? Errado! O comando wc conta novos códigos de linha, não linhas! Quando a última linha do arquivo não termina com o novo código de linha, isso não conta!

Se você ainda deseja contar linhas, use grep -c ^ , exemplo completo:

#this example prints line count for all found files
total=0
find /path -type f -name "*.php" | while read FILE; do
     #you see use grep instead wc ! for properly counting
     count=$(grep -c ^ < "$FILE")
     echo "$FILE has $count lines"
     let total=total+count #in bash, you can convert this for another shell
done
echo TOTAL LINES COUNTED:  $total

finalmente, cuidado com a armadilha wc -l (conta entra, não linhas !!!)


Por favor, leia a definição POSIX de uma linha . Com grep -c ^a contagem do número de linhas incompletas , essas linhas incompletas não podem aparecer em um arquivo de texto .
Gnourf_gniourf

2
Eu sei isso. Na prática, apenas a última linha pode estar incompleta porque não possui EOL. A idéia está contando todas as linhas, incluindo uma incompleta. É um erro muito frequente, contando apenas linhas completas. depois de contar, estamos pensando "por que eu perdi a última linha ???". Esta é a resposta por que e a receita de como fazê-lo corretamente.
Znik

Ou, se você quiser um liner: find -type f -name '*.php' -print0 | xargs -0 grep -ch ^ | paste -sd+ - | bc consulte aqui alternativas para bc: stackoverflow.com/q/926069/2400328
techniao

4

muito simplesmente

find /path -type f -name "*.php" | while read FILE
do
    count=$(wc -l < $FILE)
    echo "$FILE has $count lines"
done

1
falhará se houver um espaço ou uma nova linha em um dos nomes de arquivo
Paweł Polewicz 18/03/10

4

Se você deseja que seus resultados sejam classificados por número de linhas, basta adicionar | sortou | sort -r( -rpor ordem decrescente) à primeira resposta, da seguinte forma:

find . -name '*.php' | xargs wc -l | sort -r

1
Como a saída de xargs wc -lé numérica, seria necessário usar sort -nou sort -nr.
Dustin Ingram

4

Para Windows , a ferramenta fácil e rápida é o LocMetrics .


É muito improvável que o OP esteja no Windows se eles estiverem usando o bash.

1
O título e a descrição da pergunta @VanessaMcHale não exigem claramente uma solução unix. Portanto, a solução baseada no Windows é aceitável. Além disso, o Google me indicou esta página quando procurava uma solução semelhante.
walv

Esse comentário me ajudou. Eu tentei isso e funciona bem.
Allan F

4

Algo diferente:

wc -l `tree -if --noreport | grep -e'\.php$'`

Isso funciona bem, mas você precisa ter pelo menos um *.phparquivo na pasta atual ou em uma de suas subpastas, ou wcparar


também pode estourar ARG_MAX
Mark K Cowan

4

Se você estiver no Linux (e acredito que esteja), recomendo minha ferramenta poliglota . É dramaticamente mais rápido que um sloccountou mais cloce é mais abrangente que sloccount.

Você pode invocá-lo com

poly .

ou

poly

portanto, é muito mais fácil de usar do que algum script bash complicado.


4

É muito fácil com os zsh globs:

wc -l ./**/*.php

Se você estiver usando o bash, basta atualizar. Não há absolutamente nenhuma razão para usar o bash.


4

A ferramenta Tokei exibe estatísticas sobre o código em um diretório. Tokei mostrará o número de arquivos, o total de linhas dentro desses arquivos e o código, os comentários e os espaços em branco agrupados por idioma. Tokei também está disponível no Mac, Linux e Windows.

Um exemplo da saída de Tokei é o seguinte:

$ tokei
-------------------------------------------------------------------------------
 Language            Files        Lines         Code     Comments       Blanks
-------------------------------------------------------------------------------
 CSS                     2           12           12            0            0
 JavaScript              1          435          404            0           31
 JSON                    3          178          178            0            0
 Markdown                1            9            9            0            0
 Rust                   10          408          259           84           65
 TOML                    3           69           41           17           11
 YAML                    1           30           25            0            5
-------------------------------------------------------------------------------
 Total                  21         1141          928          101          112
-------------------------------------------------------------------------------

O Tokei pode ser instalado seguindo as instruções no arquivo README no repositório .


1
Esta deve ser a resposta aceita
Elijas

3

Se você precisar apenas do número total de linhas, digamos seus arquivos PHP, você pode usar um comando de uma linha muito simples, mesmo no Windows, se o GnuWin32 estiver instalado. Como isso:

cat `/gnuwin32/bin/find.exe . -name *.php` | wc -l

Você precisa especificar onde exatamente está o find.exe, caso contrário, o FIND.EXE fornecido pelo Windows (a partir dos antigos comandos semelhantes ao DOS) será executado, pois provavelmente antes do GnuWin32 no ambiente PATH e possui parâmetros e resultados diferentes.

Observe que no comando acima você deve usar aspas duplas, não aspas simples.


No exemplo acima, estou usando o bash para janelas, em vez do cmd.exe, por isso há barras "/" e não barras "\".
Neven Boyanov

3

Distribuindo os arquivos mais longos primeiro (ou seja, talvez esses arquivos longos precisem de um pouco de refatoração?) E excluindo alguns diretórios de fornecedores:

 find . -name '*.php' | xargs wc -l | sort -nr | egrep -v "libs|tmp|tests|vendor" | less

3

Se você quiser simplificar, recorte o intermediário e ligue wccom todos os nomes de arquivos:

wc -l `find . -name "*.php"`

Ou na sintaxe moderna:

wc -l $(find . -name "*.php")

Funciona desde que não haja espaços em nenhum dos nomes de diretório ou nomes de arquivos. E desde que você não tenha dezenas de milhares de arquivos (os shells modernos suportam linhas de comando realmente longas). Seu projeto possui 74 arquivos, portanto você tem muito espaço para crescer.


Eu gosto deste! Se você estiver no ambiente híbrido de C / C ++:wc -l `find . -type f \( -name "*.cpp" -o -name "*.c" -o -name "*.h" \) -print`
Bram

foi surpreendido que não era a resposta de topo
ms4720

3

Você não precisa de todos esses comandos complicados e difíceis de lembrar. Você só precisa de uma ferramenta chamada contador de linhas .

Uma rápida visão geral

É assim que você obtém a ferramenta

$ pip install line-counter

Use o linecomando para obter a contagem de arquivos e a linha no diretório atual (recursivamente)

$ line
Search in /Users/Morgan/Documents/Example/
file count: 4
line count: 839

Se você quiser mais detalhes, basta usar line -d.

$ line -d
Search in /Users/Morgan/Documents/Example/
Dir A/file C.c                                             72
Dir A/file D.py                                           268
file A.py                                                 467
file B.c                                                   32
file count: 4
line count: 839

E a melhor parte dessa ferramenta é que você pode adicionar .gitignoreum arquivo de configuração. Você pode configurar regras para selecionar ou ignorar que tipo de arquivos contar, exatamente como o que você faz em '.gitignore'.

Mais descrição e uso estão aqui: https://github.com/MorganZhang100/line-counter


3

Se os arquivos forem muitos, é melhor procurar apenas a contagem total de linhas.

find . -name '*.php' | xargs wc -l | grep -i ' total' | awk '{print $1}'

2

Pelo menos no OS X, os comandos find + xarg + wc listados em algumas das outras respostas imprimem "total" várias vezes em listagens grandes e não há um total completo. Consegui obter um total único para arquivos .c usando o seguinte comando:

find . -name '*.c' -print0 |xargs -0 wc -l|grep -v total|awk '{ sum += $1; } END { print "SUM: " sum; }'

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.