Contando linhas de código?

24

se eu quiser contar as linhas de código, o mais trivial é

cat *.c *.h | wc -l

Mas e se eu tiver vários subdiretórios?

Niklas
fonte
3
Fora do tópico: Por que o desnecessário cat? wc -l *.c *.hfaz a mesma coisa.
Thomas Padron-McCarthy
5
@ ThomasPadron-McCarthy Não, não. Você precisaria wc -l *.c *.h | tail -n 1obter uma saída semelhante.
Gilles 'SO- stop be evil'
2
Observe que alguns (possivelmente até a maioria) shells modernos (Bash v4, Zsh, provavelmente mais) fornecem um mecanismo recursivo de globbing usando **, para que você possa ter usado wc -l **/*.{h,c}ou algo semelhante. Observe que no Bash, pelo menos, esta opção (chamada globstar) está desativada por padrão. Mas também observe que, nesse caso específico, clocou SLOCCounté uma opção muito melhor. (Além disso, ackpode ser preferível findpara facilmente encontrar / listagem de arquivos de origem.)
Kyle Strand
5
wc -l conta linhas, não linhas de código. 7000 linhas em branco ainda serão exibidas em wc -l, mas não serão contadas em uma métrica de código. (comentários também geralmente não contam)
coteyr

Respostas:

49

A maneira mais fácil é usar a ferramenta chamada cloc. Use desta maneira:

cloc .

É isso aí. :-)

Ho1
fonte
11
-1 porque esse programa não tem como reconhecer linhas de código em idiomas fora de seu pequeno e chato cérebro. Ele conhece as linguagens Ada e Pascal e C e C ++ e Java e JavaScript e "enterprise", mas se recusa a contar o SLOC apenas com extensão de arquivo e, portanto, é completamente inútil para DSLs, ou mesmo linguagens que simplesmente não conhece. sobre.
cat
21
@cat Nada é perfeito e nada pode atender a todas as suas demandas passadas e futuras.
• Ho1
2
Bem, a linguagem de programação que CLOC se recusa a reconhecer, de fato, cumprir todas as minhas passadas e futuras demandas :)
gato
6
@cat de acordo com a documentação do CLOC que pode ler em um arquivo de definição de idioma, portanto, há uma maneira de fazê-lo reconhecer o código nos idiomas que não definiu. Além disso, é de código aberto, para que você sempre possa estendê-lo para torná-lo melhor!
Centimane
39

Você provavelmente deve usar SLOCCount ou cloc para isso, eles foram projetados especificamente para contar linhas de código-fonte em um projeto, independentemente da estrutura de diretórios etc .; ou

sloccount .

ou

cloc .

produzirá um relatório com todo o código fonte, começando no diretório atual.

Se você deseja usar finde wc, o GNU wctem uma boa --files0-fromopção:

find . -name '*.[ch]' -print0 | wc --files0-from=-

(Obrigado ao SnakeDoc pela sugestão do cloc !)

Stephen Kitt
fonte
+1 para número de slocc. Curiosamente, a execução sloccount /tmp/stackexchange(criada novamente em 17 de maio após a minha reinicialização mais recente) diz que o custo estimado para desenvolver os arquivos sh, perl, awk, etc encontrados foi de US $ 11.029. e isso não inclui os one-liners que nunca entraram em um arquivo de script.
cas
11
Estimando o custo com base em linhas de código? E todas as pessoas empregadas para re-fatorar o espaguete em algo sustentável?
Pare de prejudicar Monica
@OrangeDog, você sempre pode tentar explicar isso na sobrecarga; consulte a documentação para obter uma explicação do cálculo (com dados salariais muito antigos) e os parâmetros que você pode ajustar.
Stephen Kitt
5
cloctambém é bom: github.com/AlDanial/cloc
SnakeDoc 8/16
@StephenKitt> ainda, o principal problema é contar para trás. Ao limpar o código, você geralmente acaba com menos linhas. Claro que você pode tentar passar uma sobrecarga manual no restante do código para explicar o código removido, mas não vejo como é melhor do que adivinhar o preço inteiro em primeiro lugar.
espectros
10

Como o wccomando pode receber vários argumentos, você pode passar todos os nomes de arquivos para wco +argumento da -execação do GNU find:

find . -type f -name '*.[ch]' -exec wc -l {} +

Como alternativa, bashuse a opção shell globstarpara percorrer os diretórios recursivamente:

shopt -s globstar
wc -l **/*.[ch]

Outras conchas atravessam recursivamente por padrão (por exemplo zsh) ou têm opções semelhantes como globstar, bem, pelo menos a maioria delas.

heemail
fonte
11
+1 para não precisar instalar software não-padrão em uma máquina onde eu não tenho raiz
Bamboomy
5

Você pode usar findjunto com xargse wc:

find . -type f -name '*.h' -o -name '*.c' | xargs wc -l
coffeMug
fonte
2
(que assume caminhos de arquivo não contêm espaços em branco, novas linhas, aspas simples, duplo citações de caracteres de barra invertida embora possa também vários saída. totallinhas se várias wcs estão a ser invocado.)
Stéphane Chazelas
Talvez o wcproblema dos vários comandos possa ser resolvido através da tubulação findpara while read FILENAME; do . . .doneestruturar. E dentro do loop while use wc -l. O restante está resumindo o total de linhas em uma variável e exibindo-o.
Sergiy Kolodyazhnyy
5

Se você estiver em um ambiente onde você não tem acesso, clocetc, eu sugiro

find -name '*.[ch]' -type f -exec cat '{}' + | grep -c '[^[:space:]]'

Execução: findpesquisa recursivamente todos os arquivos regulares cujo nome termina em ou .cou .he é executado catneles. A saída é canalizada greppara contar todas as linhas não em branco (aquelas que contêm pelo menos um caractere não espaçador).

Kotte
fonte
4

Como foi apontado nos comentários, nãocat file | wc -l é equivalente a porque o primeiro imprime apenas um número, enquanto o último imprime um número e o nome do arquivo. Da mesma forma , imprimirá apenas um número, enquanto imprimirá uma linha de informações para cada arquivo.wc -l filecat * | wc -lwc -l *

No espírito da simplicidade, vamos revisitar a pergunta realmente feita:

se eu quiser contar as linhas de código, o mais trivial é

cat *.c *.h | wc -l

Mas e se eu tiver vários subdiretórios?

Em primeiro lugar, você pode simplificar até mesmo seu comando trivial para:

cat *.[ch] | wc -l

E, finalmente, o equivalente a muitos subdiretórios é:

find . -name '*.[ch]' -exec cat {} + | wc -l

Talvez isso possa ser melhorado de várias maneiras, como restringir os arquivos correspondentes apenas aos arquivos regulares (não diretórios) adicionando -type f- mas o findcomando fornecido é o equivalente recursivo exatocat *.[ch] .

Curinga
fonte
3

Amostra usando awk:

find . -name '*.[ch]' -exec wc -l {} \; |
  awk '{SUM+=$1}; END { print "Total number of lines: " SUM }'
Lambert
fonte
Use +no lugar de \;.
Jonathan Leffler
@JonathanLeffler Why?
Hastur
11
@ Hastur: Ele roda wc -lpara grupos de arquivos, da mesma forma que xargsfaz, mas lida com caracteres ímpares (como espaços) nos nomes dos arquivos sem a necessidade de um xargsou o (não padrão) -print0e as -0opções para finde xargsrespectivamente. É uma otimização menor. A desvantagem seria que cada chamada de wcproduziria uma contagem total de linhas no final quando receber vários arquivos - o awkscript lidaria com isso. Portanto, não é um slam-dunk, mas muitas vezes, usar +no lugar de \;with findé uma boa idéia.
Jonathan Leffler
@JonathanLeffler Obrigado. Concordo. Minhas preocupações, no entanto, eram sobre o comprimento da string de parâmetro passada para wc. Se a priori for desconhecido o número de arquivos que serão encontrados , existe o risco de ultrapassar esse limite ou de alguma forma ele é tratado pelo find?
Hastur
2
@Hastur: findagrupa os arquivos em pacotes de tamanho conveniente, que não excederão o limite de comprimento para a lista de argumentos na plataforma, permitindo o ambiente (que sai do comprimento da lista de argumentos - portanto, o tamanho da lista de argumentos mais o o comprimento do ambiente deve ser menor que um valor máximo). IOW, findfaz o trabalho certo, como xargsfaz o trabalho certo.
Jonathan Leffler
1

comando fácil:

find . -name '*.[ch]' | xargs wc -l
malyy
fonte
(que assume caminhos de arquivo não contêm espaços em branco, novas linhas, aspas simples, duplo citações de caracteres de barra invertida embora possa também vários saída. totallinhas se várias wcs estão a ser invocado.)
Stéphane Chazelas
0

Se você estiver no Linux, recomendo minha própria ferramenta, poliglota . É dramaticamente mais rápido cloce com mais recursos do que sloccount.

Você também deve poder usar o BSD, embora não haja binários fornecidos.

Você pode invocá-lo com

poly .

fonte
-2

find . -name \*.[ch] -print | xargs -n 1 wc -ldeve fazer o truque. Também existem várias variações possíveis, como usar em -execvez de canalizar a saída wc.

John
fonte
4
Mas find . -name \*.[ch] -printnão imprime o conteúdo dos arquivos, apenas os nomes dos arquivos. Então conto o número de arquivos, não é? Preciso de `xargs '?
Niklas
@ Programmer400 sim, você precisaria xargse também precisaria assistir a várias wcinvocações se tiver muitos arquivos; você precisaria procurar todas as totallinhas e somar.
Stephen Kitt
Se você quer apenas a contagem total da linha, você precisa fazerfind . -name \*.[ch] -print0 | xargs -0 cat | wc -l
fofo
Observe que isso ( find . -name \*.[ch] -print | wc -l) conta o número de arquivos (a menos que o nome de um arquivo contenha uma nova linha - mas isso é muito incomum) - não conta o número de linhas nos arquivos.
Jonathan Leffler