Contando líneas de código?

24

si quiero contar las líneas de código, lo trivial es

cat *.c *.h | wc -l

¿Pero qué pasa si tengo varios subdirectorios?

Niklas
fuente
3
Fuera de tema: ¿Por qué lo innecesario cat? wc -l *.c *.hhace lo mismo
Thomas Padron-McCarthy
55
@ ThomasPadron-McCarthy No, no lo hace. Necesitaría wc -l *.c *.h | tail -n 1obtener una salida similar.
Gilles 'SO- deja de ser malvado'
2
Tenga en cuenta que algunos (posiblemente incluso la mayoría) de los proyectiles modernos (Bash v4, Zsh, probablemente más) proporcionan un mecanismo recursivo de uso de globos **, por lo que podría haber utilizado wc -l **/*.{h,c}o algo similar. Tenga en cuenta que en Bash, al menos, esta opción (llamada globstar) está desactivada de forma predeterminada. Pero también tenga en cuenta que en este caso particular, cloco SLOCCountes una opción mucho mejor. (Además, ackpuede ser preferible findpara encontrar / enumerar fácilmente archivos fuente.)
Kyle Strand
55
wc -l cuenta líneas, no líneas de código. 7000 líneas en blanco seguirán apareciendo en wc -l pero no contarían en una métrica de código. (los comentarios generalmente no cuentan)
coteyr

Respuestas:

49

La forma más fácil es usar la herramienta llamada cloc. Úselo de esta manera:

cloc .

Eso es. :-)

Ho1
fuente
1
-1 porque este programa no tiene forma de reconocer líneas de código en lenguajes fuera de su pequeño y aburrido cerebro. Sabe acerca de Ada y Pascal y C y C ++ y Java y JavaScript y los lenguajes de tipo "empresarial", pero se niega a contar el SLOC solo con la extensión de archivo, y por lo tanto es completamente inútil para DSL, o incluso lenguajes que simplemente no conoce acerca de.
gato
21
@cat Nada es perfecto, y nada puede satisfacer todas sus demandas pasadas y futuras.
Ho1
2
Bueno, el lenguaje de programación que CLOC se niega a reconocer cumple con todas mis demandas pasadas y futuras :)
cat
66
@cat de acuerdo con la documentación de CLOC que puede leer en un archivo de definición de idioma, por lo que hay una manera de que reconozca el código en idiomas que no ha definido. Además, es de código abierto, por lo que siempre puede ampliarlo para mejorarlo.
Centimane
39

Probablemente debería usar SLOCCount o cloc para esto, están diseñados específicamente para contar líneas de código fuente en un proyecto, independientemente de la estructura del directorio, etc .; ya sea

sloccount .

o

cloc .

producirá un informe sobre todo el código fuente a partir del directorio actual.

Si quieres usar findy wc, GNU wctiene una buena --files0-fromopción:

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

(¡Gracias a SnakeDoc por la sugerencia de cloc !)

Stephen Kitt
fuente
+1 para cuenta atrás. Curiosamente, la ejecución sloccount /tmp/stackexchange(creada nuevamente el 17 de mayo después de mi reinicio más reciente) dice que el costo estimado para desarrollar los archivos sh, perl, awk, etc. que encontró es de $ 11,029. y eso no incluye las frases que nunca se convirtieron en un archivo de script.
cas
11
Estimando el costo basado en líneas de código? ¿Qué pasa con todas las personas empleadas para re-factorizar los espaguetis en algo sostenible?
Deja de dañar a Monica el
@OrangeDog, siempre puedes intentar dar cuenta de eso en los gastos generales; Consulte la documentación para obtener una explicación del cálculo (con datos salariales muy antiguos) y los parámetros que puede modificar.
Stephen Kitt
55
cloctambién es bueno: github.com/AlDanial/cloc
SnakeDoc
@StephenKitt> aún así, el problema principal es que está contando hacia atrás. Al limpiar el código, a menudo terminas con menos líneas. Claro que podría intentar mover manualmente una sobrecarga para incurrir en el resto del código para tener en cuenta el eliminado, pero no veo cómo es mejor que simplemente adivinar el precio completo en primer lugar.
espectras
10

Como el wccomando puede tomar múltiples argumentos, puede pasar todos los nombres de archivo para wcusar el +argumento de la -execacción de GNU find:

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

Alternativamente, en bash, usando la opción de shell globstarpara recorrer los directorios de forma recursiva:

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

Otros shells atraviesan recursivamente por defecto (p zsh. Ej. ) O tienen opciones similares como globstar, bueno, al menos la mayoría.

heemayl
fuente
1
+1 por no necesitar instalar software no estándar en una máquina donde no tengo root
Bamboomy
5

Puede usar findjunto con xargsy wc:

find . -type f -name '*.h' -o -name '*.c' | xargs wc -l
taza de cafe
fuente
2
(eso supone que las rutas de archivo no contienen espacios en blanco, líneas nuevas, comillas simples, comillas dobles de caracteres de barra invertida. También puede generar varias totallíneas si wcse invocan varios s).
Stéphane Chazelas
Quizás el wcproblema de varios comandos puede abordarse canalizando finda la while read FILENAME; do . . .doneestructura. Y dentro del uso del bucle while wc -l. El resto es resumir las líneas totales en una variable y mostrarla.
Sergiy Kolodyazhnyy
5

Si se encuentra en un entorno donde no tiene acceso, clocetc., le sugiero

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

Recorrido: findbusca de forma recursiva todos los archivos normales cuyo nombre termina en o .co .hy se ejecuta caten ellos. La salida se canaliza greppara contar todas las líneas que no están en blanco (las que contienen al menos un carácter sin espaciado).

Kotte
fuente
4

Como se ha señalado en los comentarios, nocat file | wc -l es equivalente a porque el primero imprime solo un número mientras que el segundo imprime un número y el nombre del archivo. Del mismo modo , imprimirá solo un número, mientras que imprimirá una línea de información para cada archivo.wc -l filecat * | wc -lwc -l *

En un espíritu de simplicidad, volvamos a la pregunta que realmente se hizo:

si quiero contar las líneas de código, lo trivial es

cat *.c *.h | wc -l

¿Pero qué pasa si tengo varios subdirectorios?

En primer lugar, puede simplificar incluso su comando trivial para:

cat *.[ch] | wc -l

Y finalmente, el equivalente de muchos subdirectorios es:

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

Quizás esto podría mejorarse de muchas maneras, como restringir los archivos coincidentes solo a archivos normales (no directorios) agregando, -type fpero el findcomando dado es el equivalente recursivo exacto de cat *.[ch].

Comodín
fuente
3

Muestra usando awk:

find . -name '*.[ch]' -exec wc -l {} \; |
  awk '{SUM+=$1}; END { print "Total number of lines: " SUM }'
Lambert
fuente
Uso +en lugar de \;.
Jonathan Leffler
@JonathanLeffler ¿Por qué?
Hastur
1
@Hastur: se ejecuta wc -lpara grupos de archivos, más o menos como lo xargshace, pero maneja caracteres extraños (como espacios) en los nombres de los archivos sin necesidad de ninguno de xargslos dos (no estándar) -print0y -0opciones findy xargsrespectivamente. Es una optimización menor. La desventaja sería que cada invocación de wcgeneraría un recuento total de líneas al final cuando se le otorgan múltiples archivos; el awkscript se ocuparía de eso. Por lo tanto, no es un slam-dunk, pero muy a menudo, usar +en lugar de \;con findes una buena idea.
Jonathan Leffler
@ JonathanLeffler Gracias. Estoy de acuerdo. Sin embargo, mis preocupaciones eran sobre la longitud de la cadena de parámetros que se pasó wc. Si se desconoce a priori el número de archivos que se encontrarán , ¿existe el riesgo de pasar ese límite o de alguna manera se maneja mediante find?
Hastur
2
@Hastur: findagrupa los archivos en paquetes de tamaño conveniente, que no excederá el límite de longitud para la lista de argumentos en la plataforma, permitiendo el entorno (que sale de la longitud de la lista de argumentos, por lo que la longitud de la lista de argumentos más el La longitud del entorno debe ser inferior a un valor máximo). IOW, findhace bien el trabajo, como xargshace bien el trabajo.
Jonathan Leffler
1

comando fácil:

find . -name '*.[ch]' | xargs wc -l
malyy
fuente
(eso supone que las rutas de archivo no contienen espacios en blanco, líneas nuevas, comillas simples, comillas dobles de caracteres de barra invertida. También puede generar varias totallíneas si wcse invocan varios s).
Stéphane Chazelas
0

Si estás en Linux, te recomiendo mi propia herramienta, polyglot . Es dramáticamente más rápido clocy con más funciones que sloccount.

También debería poder construir en BSD, aunque no hay ningún binario proporcionado.

Puedes invocarlo con

poly .

fuente
-2

find . -name \*.[ch] -print | xargs -n 1 wc -ldebería hacer el truco. También hay varias variaciones posibles sobre eso, como usar en -execlugar de canalizar la salida a wc.

John
fuente
44
Pero find . -name \*.[ch] -printno imprime el contenido de los archivos, solo los nombres de los archivos. Entonces, cuento la cantidad de archivos, ¿no? ¿Necesito 'xargs'?
Niklas
@ Programmer400 sí, necesitaría xargs, y también necesitaría estar atento a las wcinvocaciones múltiples si tiene muchos archivos; deberías buscar todas las totallíneas y sumarlas.
Stephen Kitt
Si solo desea el recuento total de líneas, debe hacerlofind . -name \*.[ch] -print0 | xargs -0 cat | wc -l
esponjoso
Tenga en cuenta que esto ( find . -name \*.[ch] -print | wc -l) cuenta el número de archivos (a menos que el nombre de un archivo contenga una nueva línea, pero eso es muy inusual), no cuenta el número de líneas en los archivos.
Jonathan Leffler