contar líneas de código (no en blanco) en bash

151

En Bash, ¿cómo cuento el número de líneas de código que no están en blanco en un proyecto?

Jonathan Hartley
fuente
1
Muchas de las soluciones a continuación solo funcionan para un archivo (por ejemplo foo.c). ¿Alguna idea sobre el número total de líneas en un proyecto (por ejemplo, muchos archivos en la estructura de directorios y excluyendo archivos binarios)?
resolvePuzzles
55
@solvingPuzzles Creo que puedo responder esa parte. Para cualquier solución que funcione en un archivo, por ejemplo, "cat FILE | sed blah", puede trabajar en muchos archivos reemplazando "cat FILE" con un comando que enumera los nombres de archivo para operar, por ejemplo, "find. -Name '* .py '", y póngalo en" xargs cat ". por ejemplo, "find. -name '* .py' | xargs cat | sed '/ ^ \ s * $ / d' | wc -l"
Jonathan Hartley
2
@JonathanHartley @solvingPuzzles también hay programas como slocy clocque están aquí para hacer esos recuentos de líneas de código.
ASTOR
OP aquí: cuando pregunté por primera vez este problema, 'cloc' no hizo un muy buen trabajo en el código Python. Hoy en día es genial.
Jonathan Hartley
cloc también está disponible como módulo npm y ahorra mucho tiempo.
Krishna Vedula

Respuestas:

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

Y si considera comentarios líneas en blanco:

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

Aunque, eso depende del idioma.

Michael Cramer
fuente
24
No estoy seguro de por qué estás usando gato allí. Use foo.c o foo.pl como nombre de archivo para pasar a sed. sed '/ ^ \ s * $ / d' foo.c | wc -l
Andy Lester
28
Solo hábito. Leo las canalizaciones de izquierda a derecha, lo que significa que generalmente empiezo con cat, luego acción, acción, acción, etc. Claramente, el resultado final es el mismo.
Michael Cramer
32
Para hacer esto para todos los archivos en todas las subcarpetas y para excluir comentarios con '//', extienda este comando a esto: find. -tipo f -name '* .c' -exec cat {} \; El | sed '/ ^ \ s * # / d; / ^ \ s * $ / d; / ^ \ s * \ / \ // d' | wc -l
Benjamin Intal
11
Usted puede leer de izquierda a derecha sin UUOC: < foo.pl sed 'stuff' | wc -l.
jw013
22
En términos generales, UUOC no es importante, pero la legibilidad sí lo es.
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

Lo anterior le dará el recuento total de líneas de código (líneas en blanco eliminadas) para un proyecto (carpeta actual y todas las subcarpetas de forma recursiva).

En el "./blog" "./punbb" "./js/3rdparty" y "./pma" anteriores están las carpetas que incluí en la lista negra ya que no escribí el código en ellas. También .php, .as, .sql, .css, .js son las extensiones de los archivos que se están mirando. Cualquier archivo con una extensión diferente se ignora.

Gilles
fuente
1
variación para una aplicación Rails: buscar. -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
1
Debe agregar un $a grep ( ...\.js$|...) de lo contrario coincidirá feature.js.swp.
Xeoncross
Olvidó el anclaje, por lo que incluye archivos incorrectos. Y una versión aún más simple con anclaje:find . | egrep '.\.c$|.\.h$' | xargs cat | sed '/^\s*$/d' | wc -l
Mark Jeronimus
36

Si desea utilizar algo más que un script de shell, intente CLOC :

cloc cuenta líneas en blanco, líneas de comentarios y líneas físicas de código fuente en muchos lenguajes de programación. Está escrito completamente en Perl sin dependencias fuera de la distribución estándar de Perl v5.6 y superior (el código de algunos módulos externos está incrustado dentro de cloc) y, por lo tanto, es bastante portátil.

xsl
fuente
2
Cuando hice esta pregunta por primera vez, 'cloc' contaba las cadenas de documentos de Python como líneas de código, lo cual era un IMO subóptimo. Las versiones modernas de 'cloc' ahora cuentan las cadenas de documentos de Python como comentarios, lo que me gusta mucho más.
Jonathan Hartley
¡Esta es la respuesta correcta! Acabo de intentar salir y funciona bien.
LeeMobile
31

Hay muchas maneras de hacer esto, utilizando utilidades de shell comunes.

Mi solución es:

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

Esto busca líneas en <archivo> las líneas que no coinciden (-v) que coinciden con el patrón (-e) '^ \ s * $', que es el comienzo de una línea, seguido de 0 o más espacios en blanco, seguidos al final de una línea (es decir, sin contenido que no sea el espacio en blanco) y muestre un recuento de líneas coincidentes (-c) en lugar de las líneas coincidentes.

Una ventaja de este método sobre los métodos que involucran la conexión wces que puede especificar varios archivos y obtener un recuento separado para cada archivo:

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

config.hh:36
exceptions.hh:48
layer.hh:52
main.hh:39
SpoonMeiser
fuente
2
¡Gracias! Por cierto, wc proporciona un recuento para cada archivo dado, más un total.
Jonathan Hartley
1
Sin embargo, no si lo está conectando, como estándar en cuentas como un solo archivo.
SpoonMeiser
Esta es la mejor respuesta en mi opinión.
simhumileco
-eno es necesario. Esa es la ubicación posicional normal del patrón y no estás haciendo nada raro con él. Pero no tiene nada de malo ser explícito, si ese es tu estilo.
Jacktose
13

'wc' cuenta líneas, palabras, caracteres, así que para contar todas las líneas (incluidas las en blanco) use:

wc *.py

Para filtrar las líneas en blanco, puede usar grep:

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

'-v' le dice a grep que muestre todas las líneas excepto aquellas que coinciden con '^' es el comienzo de una línea '\ s *' es cero o más espacios en blanco '$' es el final de una línea * .py es mi ejemplo para Todos los archivos que desea contar (todos los archivos de Python en el directorio actual) se envían a wc. Ya te vas.

Estoy respondiendo mi propia pregunta (genuina). No se pudo encontrar una entrada de stackoverflow que cubriera esto.

Jonathan Hartley
fuente
55
\ W no es una coincidencia para espacios en blanco, coincide con caracteres que no son palabras. Es lo opuesto a \ w, caracteres de palabras. \ W Emparejará todo lo que no sea alfanumérico o subrayado, y por lo tanto no hará lo que usted dice que hace aquí. Quieres decir \ s
SpoonMeiser
9

Este comando cuenta el número de líneas no en blanco.
cat fileName | grep -v ^$ | wc -l
grep -v ^ $ la función de expresión regular es ignorar líneas en blanco.

línea costera
fuente
Esta respuesta es la más directa
Samthebest
2
No hay necesidad caten esta cadena:grep -v ^$ fileName | wl -l
Aethalides
77
Tampoco es necesario wc -lporque grep tiene -c:grep -vc ^$ fileName
Jacktose
6
cat file.txt | awk 'NF' | wc -l
Jaydillan
fuente
amo la simplicidad de este 👏🏼
Gerard
5
cat 'filename' | grep '[^ ]' | wc -l

debería hacer el truco bien

curtisk
fuente
3
¿Por qué usar cat y canalizar el archivo en grep, cuando puede pasar el nombre de archivo como argumento para grep en primer lugar?
SpoonMeiser
Es cierto, es solo un viejo alias que tengo alrededor ... hace esencialmente lo mismo que su solución en lugar de usar el inverso
curtisk
4
awk '/^[[:space:]]*$/ {++x} END {print x}' "$testfile"
Ben Hoffstein
fuente
1
Yo votaría por esto solo porque literalmente nunca he visto a nadie usar preincrement en un script awk, pero desafortunadamente esto solo cuenta las líneas en blanco. :) ¿Quieres decir awk '!/^[[:space:]]*$/{++x} END{print x}'? O, si realmente odias los 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

Publico esto porque otras opciones me dieron respuestas incorrectas. Esto funcionó con mi fuente de Java, donde las líneas de comentarios comienzan con / o * (uso * en cada línea en comentarios de varias líneas).

sami
fuente
Esta es una solución viable. Lo único a tener en cuenta: no cuenta los comentarios de varias líneas
Amol
2

Aquí hay un script Bash que cuenta las líneas de código en un proyecto. Atraviesa un árbol de origen de forma recursiva y excluye las líneas en blanco y los comentarios de una sola línea que usan "//".

# $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

Así es como se ve la salida para mi proyecto :

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

¡Disfrutar! - Curran

curran
fuente
1

Depende un poco de la cantidad de archivos que tenga en el proyecto. En teoría podrías usar

grep -c '.' <list of files>

Donde puede llenar la lista de archivos utilizando la utilidad find.

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

Te daría un recuento de líneas por archivo.

Linor
fuente
1
. coincide con espacios en blanco. Esta solución solo funciona si considera que una línea que contiene solo espacios en blanco no está en blanco, lo que técnicamente es, aunque probablemente no sea lo que busca.
SpoonMeiser
1

Script para contar recursivamente todas las líneas no en blanco con una determinada extensión de archivo en el directorio actual:

#!/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 de la muestra:

./countlines.sh .py .java .html
Keith Pinson
fuente
Gracias a @Andy Lester (+1 en su comentario) por la parte "no en blanco" de la receta.
Keith Pinson
Gracias también a @Michael Cramer (+1 en su publicación) por publicar originalmente la solución "no en blanco" (un poco más detallada).
Keith Pinson
1

Si desea la suma de todas las líneas que no están en blanco para todos los archivos de una extensión de archivo dada en un proyecto:

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

El primer argumento es el directorio base del proyecto, el segundo es la extensión del archivo. Uso de la muestra:

./scriptname ~/Dropbox/project/src java

Es poco más que una colección de soluciones anteriores.

Andy
fuente
Este obtiene el premio por la mayor cantidad de llamadas fork + exec al iniciar grep una vez por línea en cada archivo. ;)
dannysauer
0
grep -v '^\W*$' `find -type f` | grep -c '.' > /path/to/lineCountFile.txt

da un recuento agregado para todos los archivos en el directorio actual y sus subdirectorios.

HTH!

holandés
fuente
\ W es caracteres que no son palabras; esto no coincidirá con una línea como ${-[*]} + $@, por ejemplo. Que seguramente es un código válido en algún lugar del mundo. ;) Te refieres a \ s para el espacio.
dannysauer
0

Esto proporciona el recuento de la cantidad de líneas sin contar las líneas en blanco:

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

da el recuento de líneas no en blanco en el directorio de trabajo actual.

jean-emmanuel
fuente
-3

Ya hay un programa para esto en Linux llamado 'wc'.

Sólo

wc -l *.c 

y le da el total de líneas y las líneas para cada archivo.

G1i1ch
fuente
3
Oye. 'wc' por sí solo no busca subdirecciones, y no filtra las líneas en blanco, ambas solicitadas explícitamente en la pregunta.
Jonathan Hartley
wccuenta líneas en blanco. El OP quiere contar líneas no en blanco. Es cierto que tendrá que usar wc, pero sólo después de que ha sido corriente editada usandosed
EhevuTov