contar linhas de código (não em branco) no bash

151

No Bash, como posso contar o número de linhas de código não em branco em um projeto?

Jonathan Hartley
fonte
1
Muitas das soluções abaixo funcionam apenas para um arquivo (por exemplo foo.c). Alguma idéia sobre o número total de linhas em um projeto (por exemplo, muitos arquivos na estrutura de diretórios e exclusão de arquivos binários)?
precisa saber é o seguinte
5
@solvingPuzzles Acho que posso responder a essa parte. Para qualquer solução que funcione em um arquivo, por exemplo, "cat FILE | sed blah", você pode trabalhar em muitos arquivos substituindo "cat FILE" por um comando que lista os nomes de arquivos nos quais operar, por exemplo, "find. -Name '* .py '"e canalize-o para" xargs cat ". por exemplo, "find. -name '* .py' | xargs cat | sed '/ ^ \ s * $ / d' | wc -l"
Jonathan Hartley
2
@JonathanHartley @solvingPuzzles há também programas como sloce clocque estamos aqui para fazer essas código linhas contagem.
AsTeR 17/02
OP aqui: Quando perguntei esse problema, o 'cloc' não fez um bom trabalho no código Python. Hoje em dia é ótimo.
Jonathan Hartley
O cloc também está disponível como um módulo npm e economiza muito tempo.
Krishna Vedula

Respostas:

193
cat foo.c | sed '/^\s*$/d' | wc -l

E se você considerar os comentários em linhas em branco:

cat foo.pl | sed '/^\s*#/d;/^\s*$/d' | wc -l

Embora isso seja dependente da linguagem.

Michael Cramer
fonte
24
Não sei por que você está usando gato lá. Use foo.c ou foo.pl como o nome do arquivo para passar para sed. sed '/ ^ \ s * $ / d' foo.c | wc -l
Andy Lester
28
Apenas hábito. Eu li os pipelines da esquerda para a direita, o que significa que geralmente começo com gato, depois ação, ação, ação etc. Claramente, o resultado final é o mesmo.
Michael Cramer
32
Para fazer isso em todos os arquivos de todas as subpastas e excluir comentários com '//', estenda este comando para isso: find. -type f -name '* .c' -exec cat {} \; | / / \ \ * * / /; // ^ \ s * $ / d; / ^ \ s * \ / \ // d '| wc -l
Benjamin Intal
11
Você pode ler esquerda para a direita, sem UUOC: < foo.pl sed 'stuff' | wc -l.
achou
22
De um modo geral, o UUOC não é importante, mas a legibilidade é.
22712 Andersand
52
#!/bin/bash
find . -path './pma' -prune -o -path './blog' -prune -o -path './punbb' -prune -o -path './js/3rdparty' -prune -o -print | egrep '\.php|\.as|\.sql|\.css|\.js' | grep -v '\.svn' | xargs cat | sed '/^\s*$/d' | wc -l

A descrição acima fornecerá a contagem total de linhas de código (linhas em branco removidas) para um projeto (pasta atual e todas as subpastas recursivamente).

Nas opções "./blog" "./punbb" "./js/3rdparty" e "./pma" acima estão as pastas que eu lista negra, pois não escrevi o código nelas. Também .php, .as, .sql, .css, .js são as extensões dos arquivos que estão sendo visualizados. Quaisquer arquivos com uma extensão diferente são ignorados.

Gilles
fonte
1
variação para um aplicativo Rails: encontre. -path './log' -prune -o -path './trunk' -prune -o -path './branches' -prune -o -path './vendor' -prune -o -path './tmp '-prune -o -print | egrep '\ .rb | \ .erb | \ .css | \ .js | \ .yml' | grep -v 'svn' | gato xargs | sed '/ ^ \ s * $ / d' | wc -l
poseid 17/03/12
1
Você precisa adicionar um $ao grep ( ...\.js$|...), caso contrário ele corresponderá feature.js.swp.
Xeoncross
Você esqueceu a ancoragem, por isso inclui arquivos errados. E uma versão ainda mais simples com ancoragem:find . | egrep '.\.c$|.\.h$' | xargs cat | sed '/^\s*$/d' | wc -l
Mark Jeronimus
36

Se você deseja usar algo diferente de um script de shell, tente CLOC :

O cloc conta linhas em branco, linhas de comentários e linhas físicas do código fonte em muitas linguagens de programação. Ele foi escrito inteiramente em Perl, sem dependências fora da distribuição padrão do Perl v5.6 e superior (o código de alguns módulos externos está incorporado no cloc) e, portanto, é bastante portátil.

xsl
fonte
2
Quando eu fiz essa pergunta, o 'cloc' contava as doutrinas do Python como linhas de código, o que era um IMHO abaixo do ideal. As versões modernas de 'cloc' agora contam como docstrings do Python como comentários, das quais eu gosto muito mais.
Jonathan Hartley
Essa é a resposta correta! Eu apenas tentei cloc e faz o trabalho bem.
21719 LeeMobile
31

Há muitas maneiras de fazer isso, usando utilitários comuns do shell.

Minha solução é:

grep -cve '^\s*$' <file>

Ele procura por linhas no <arquivo> as linhas que não correspondem (-v) que correspondem ao padrão (-e) '^ \ s * $', que é o início de uma linha, seguido por 0 ou mais caracteres de espaço em branco, seguidos no final de uma linha (ou seja, nenhum conteúdo que não seja espaço em branco) e exiba uma contagem de linhas correspondentes (-c) em vez das próprias linhas correspondentes.

Uma vantagem desse método em relação aos métodos que envolvem canalização wcé que você pode especificar vários arquivos e obter uma contagem separada para cada arquivo:

$ grep -cve '^\s*$' *.hh

config.hh:36
exceptions.hh:48
layer.hh:52
main.hh:39
SpoonMeiser
fonte
2
Obrigado! Aliás, o wc fornece uma contagem para cada arquivo fornecido, mais um total.
9139 Jonathan Hartley
1
Não, se você estiver trabalhando nisso, como padrão, conta apenas como um arquivo.
SpoonMeiser 10/11/2009
Esta é a melhor resposta na minha opinião.
simhumileco
-enão é necessário. Essa é a localização posicional normal do padrão e você não está fazendo nada divertido com ele. Mas nada de errado em ser explícito, se esse é o seu estilo.
Jacktose 12/03/19
13

'wc' conta linhas, palavras, caracteres, para contar todas as linhas (incluindo as em branco) use:

wc *.py

Para filtrar as linhas em branco, você pode usar grep:

grep -v '^\s*$' *.py | wc

'-v' diz ao grep para produzir todas as linhas, exceto aquelas que correspondem a '^' é o início de uma linha '\ s *' é zero ou mais caracteres em branco '$' é o final de uma linha * .py é o meu exemplo para todos os arquivos que você deseja contar (todos os arquivos python no diretório atual) canalizam a saída para o wc. Lá vai você.

Estou respondendo minha própria pergunta (genuína). Não foi possível encontrar uma entrada de stackoverflow que cobria isso.

Jonathan Hartley
fonte
5
\ W não corresponde a espaços em branco, corresponde a caracteres que não são de palavra. É o oposto de \ w, caracteres da palavra. \ W Corresponderá a qualquer coisa que não seja alfanumérica ou sublinhada e, portanto, não fará o que você afirma aqui. Quer dizer \ s
SpoonMeiser
9

Este comando conta o número de linhas que não estão em branco.
cat fileName | grep -v ^$ | wc -l
A função de expressão regular grep -v ^ $ ignora as linhas em branco.

litoral
fonte
Esta resposta é a mais direta
samthebest 13/03/18
2
Não há necessidade de catnesta cadeia:grep -v ^$ fileName | wl -l
Aethalides
7
Também não há necessidade, wc -lporque o grep tem -c:grep -vc ^$ fileName
Jacktose
6
cat file.txt | awk 'NF' | wc -l
Jaydillan
fonte
amo a simplicidade deste 👏🏼
Gerard
5
cat 'filename' | grep '[^ ]' | wc -l

deve fazer o truque muito bem

curtisk
fonte
3
Por que usar cat e canalizar o arquivo no grep, quando você pode passar o nome do arquivo como argumento para grep em primeiro lugar?
SpoonMeiser 22/09/08
verdade, é apenas um alias de idade eu tenho em torno ... ele essencialmente o mesmo que a sua solução em vez de usar o inverso
curtisk
4
awk '/^[[:space:]]*$/ {++x} END {print x}' "$testfile"
Ben Hoffstein
fonte
1
Eu votaria nisso apenas porque nunca vi alguém usar pré-incremento em um script awk, mas infelizmente isso conta apenas as linhas em branco. :) Você quer dizer awk '!/^[[:space:]]*$/{++x} END{print x}'. Ou, se você realmente odeia negativos, awk '{y++} /^[[:space:]]*$/{++x} END{print y-x}';)
dannysauer
4
grep -cvE '(^\s*[/*])|(^\s*$)' foo

-c = count
-v = exclude
-E = extended regex
'(comment lines) OR (empty lines)'
where
^    = beginning of the line
\s   = whitespace
*    = any number of previous characters or none
[/*] = either / or *
|    = OR
$    = end of the line

Eu posto isso porque outras opções deram respostas erradas para mim. Isso funcionou com minha fonte java, onde as linhas de comentário começam com / ou * (eu uso * em todas as linhas no comentário de várias linhas).

sami
fonte
Esta é uma solução viável. A única coisa a aviso: não conta comentários ramal
Amol
2

Aqui está um script Bash que conta as linhas de código em um projeto. Ele percorre uma árvore de origem recursivamente e exclui linhas em branco e comentários de linha única que usam "//".

# $excluded is a regex for paths to exclude from line counting
excluded="spec\|node_modules\|README\|lib\|docs\|csv\|XLS\|json\|png"

countLines(){
  # $total is the total lines of code counted
  total=0
  # -mindepth exclues the current directory (".")
  for file in `find . -mindepth 1 -name "*.*" |grep -v "$excluded"`; do
    # First sed: only count lines of code that are not commented with //
    # Second sed: don't count blank lines
    # $numLines is the lines of code
    numLines=`cat $file | sed '/\/\//d' | sed '/^\s*$/d' | wc -l`

    # To exclude only blank lines and count comment lines, uncomment this:
    #numLines=`cat $file | sed '/^\s*$/d' | wc -l`

    total=$(($total + $numLines))
    echo "  " $numLines $file
  done
  echo "  " $total in total
}

echo Source code files:
countLines
echo Unit tests:
cd spec
countLines

Aqui está a aparência da saída para o meu projeto :

Source code files:
   2 ./buildDocs.sh
   24 ./countLines.sh
   15 ./css/dashboard.css
   53 ./data/un_population/provenance/preprocess.js
   19 ./index.html
   5 ./server/server.js
   2 ./server/startServer.sh
   24 ./SpecRunner.html
   34 ./src/computeLayout.js
   60 ./src/configDiff.js
   18 ./src/dashboardMirror.js
   37 ./src/dashboardScaffold.js
   14 ./src/data.js
   68 ./src/dummyVis.js
   27 ./src/layout.js
   28 ./src/links.js
   5 ./src/main.js
   52 ./src/processActions.js
   86 ./src/timeline.js
   73 ./src/udc.js
   18 ./src/wire.js
   664 in total
Unit tests:
   230 ./ComputeLayoutSpec.js
   134 ./ConfigDiffSpec.js
   134 ./ProcessActionsSpec.js
   84 ./UDCSpec.js
   149 ./WireSpec.js
   731 in total

Aproveitar! - Curran

curran
fonte
1

Depende do número de arquivos que você possui no projeto. Em teoria, você poderia usar

grep -c '.' <list of files>

Onde você pode preencher a lista de arquivos usando o utilitário de localização.

grep -c '.' `find -type f`

Daria a você uma contagem de linhas por arquivo.

Linor
fonte
1
. corresponde a espaço em branco. Essa solução só funciona se você considerar uma linha que contém apenas espaços em branco como não em branco, o que tecnicamente é, embora provavelmente não seja isso que você procura.
SpoonMeiser 22/09/08
1

Script para contar recursivamente todas as linhas que não estão em branco com uma certa extensão de arquivo no diretório atual:

#!/usr/bin/env bash
(
echo 0;
for ext in "$@"; do
    for i in $(find . -name "*$ext"); do
        sed '/^\s*$/d' $i | wc -l ## skip blank lines
        #cat $i | wc -l; ## count all lines
        echo +;
    done
done
echo p q;
) | dc;

Uso da amostra:

./countlines.sh .py .java .html
Keith Pinson
fonte
Obrigado, vá para @Andy Lester (+1 no seu comentário) pela parte "não em branco" da receita.
perfil completo de Keith Pinson
Agradecemos também a @ Michael Cramer (+1 em sua postagem) por postar originalmente a solução "um pouco mais detalhada" "em branco".
perfil completo de Keith Pinson
1

Se você deseja a soma de todas as linhas não em branco de todos os arquivos de uma determinada extensão de arquivo em um projeto:

while read line
do grep -cve '^\s*$' "$line"
done <  <(find $1 -name "*.$2" -print) | awk '{s+=$1} END {print s}'

O primeiro argumento é o diretório base do projeto, o segundo é a extensão do arquivo. Uso da amostra:

./scriptname ~/Dropbox/project/src java

É pouco mais do que uma coleção de soluções anteriores.

Andy
fonte
Este recebe o prêmio pelo maior número de chamadas fork + exec, iniciando grep uma vez por linha em cada arquivo. ;)
dannysauer
0
grep -v '^\W*$' `find -type f` | grep -c '.' > /path/to/lineCountFile.txt

fornece uma contagem agregada para todos os arquivos no diretório atual e seus subdiretórios.

HTH!

holandês
fonte
\ W é caracteres que não são da palavra; isso não corresponde a uma linha como ${-[*]} + $@, por exemplo. O que certamente é um código válido em algum lugar do mundo. ;) Você quer dizer \ espaço.
dannysauer
0

Isso fornece a contagem do número de linhas sem contar as linhas em branco:

grep -v ^$ filename wc -l | sed -e 's/ //g' 
mahesh
fonte
0
rgrep . | wc -l

fornece a contagem de linhas não em branco no diretório de trabalho atual.

jean-emmanuel
fonte
-3

Já existe um programa para isso no linux chamado 'wc'.

Somente

wc -l *.c 

e fornece o total de linhas e as linhas para cada arquivo.

G1i1ch
fonte
3
Ei. 'wc' por si só não pesquisa subdiretórios e não filtra linhas em branco, ambas solicitadas explicitamente na pergunta.
Jonathan Hartley
wcconta linhas em branco. O OP quer contar linhas não em branco. É verdade que ele vai querer usar wc, mas só depois de ter sido corrente editada usandosed
EhevuTov