Cómo contar líneas de código incluyendo subdirectorios [duplicar]


Esta pregunta ya tiene una respuesta aquí:

Supongamos que quiero contar las líneas de código en un proyecto. Si todos los archivos están en el mismo directorio puedo ejecutar:

cat * | wc -l

Sin embargo, si hay subdirectorios, esto no funciona. Para que esto funcione, cat lo haría tiene que tener un modo recursivo. Sospecho que esto podría ser un trabajo para xargs, pero me pregunto si hay una solución más elegante?

Author: madth3, 2008-11-25

11 answers

Primero no es necesario usar cat para contar líneas. Este es un antipatrón llamado Uso Inútil del Gato (UUoC). Para contar las líneas de los archivos del directorio actual, utilice wc:

wc -l * 

Entonces el comando find recurre a los subdirectorios:

find . -name "*.c" -exec wc -l {} \;
  • . es el nombre del directorio superior desde el que se inicia la búsqueda

  • -name "*.c" es el patrón del archivo que te interesa

  • -exec da una orden a ser ejecutado

  • {} es el resultado del comando find que se pasa al comando (aquí wc-l)

  • \; indica el final del comando

Este comando produce una lista de todos los archivos encontrados con su recuento de líneas, si desea tener la suma de todos los archivos encontrados, puede usar find para listar los archivos (con la opción -print) y luego usar xargs para pasar esta lista como argumento a wc-l.

find . -name "*.c" -print | xargs wc -l 

EDITAR a dirección Robert Gamble comentario (gracias): si usted tiene espacios o nuevas líneas (!) en nombres de archivo, entonces usted tiene que usar la opción -print0 en lugar de -print y xargs -null para que la lista de nombres de archivo se intercambien con cadenas terminadas en null.

find . -name "*.c" -print0 | xargs -0 wc -l

La filosofía de Unix es tener herramientas que hagan una sola cosa, y lo hagan bien.

 150
Author: philant,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-29 03:09:05

Si quieres una respuesta de código de golf:

grep '' -R . | wc -l 

El problema con solo usar wc-l por sí solo es que no puede descender bien, y los únicos que usan

find . -exec wc -l {} \;

No le dará un recuento total de líneas porque ejecuta wc una vez por cada archivo, (loL! ) y

find . -exec wc -l {} + 

Se confunden tan pronto como encontrar golpea el ~200k1,2 argumento de carácter límite de los parámetros y en lugar de llamadas wc múltiples veces, cada vez sólo te doy un resumen parcial.

Además, el truco grep anterior no agregará más de 1 línea a la salida cuando encuentre un archivo binario, lo que podría ser circunstancialmente beneficioso.

Por el costo de 1 carácter de comando adicional, puede ignorar completamente los archivos binarios:

 grep '' -IR . | wc -l

Si desea ejecutar recuentos de líneas en archivos binarios también

 grep '' -aR . | wc -l 
Nota a pie de página sobre los límites:

Los documentos son un poco vagos en cuanto a si es un límite de tamaño cadena o un número de tokens límite.

cd /usr/include;
find -type f -exec perl -e 'printf qq[%s => %s\n], scalar @ARGV, length join q[ ], @ARGV' {} + 
# 4066 => 130974
# 3399 => 130955
# 3155 => 130978
# 2762 => 130991
# 3923 => 130959
# 3642 => 130989
# 4145 => 130993
# 4382 => 130989
# 4406 => 130973
# 4190 => 131000
# 4603 => 130988
# 3060 => 95435

Esto implica que va a chunk muy muy fácilmente.

 29
Author: Kent Fredric,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:34:15

Creo que probablemente estás atascado con xargs

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

El método de Chromakode da el mismo resultado pero es mucho más lento. Si usa xargs, sucat ing ywc ing pueden comenzar tan pronto como find comience a buscar.

Buena explicación en Linux: xargs vs exec {}

 13
Author: Ken,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:25:58

Intente usar el comando find, que recurde directorios por defecto:

find . -type f -execdir cat {} \; | wc -l

 10
Author: chromakode,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-25 07:41:51

La forma correcta es:

find . -name "*.c" -print0 | xargs -0 cat | wc -l

Debe usar-print0 porque solo hay dos caracteres no válidos en los nombres de archivo Unix: El byte nulo y "/" (barra diagonal). Por ejemplo," xxx\npasswd " es un nombre válido. En realidad, es más probable encontrar nombres con espacios en ellos, sin embargo. Los comandos anteriores contarían cada palabra como un archivo separado.

También puede usar "-type f" en lugar de-name para limitar la búsqueda a archivos.

 9
Author: Aaron Digulla,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-25 16:12:53

Usar cat o grep en las soluciones anteriores es un desperdicio si puede usar herramientas GNU relativamente recientes, incluyendo Bash:

wc -l --files0-from=<(find . -name \*.c -print0)

Esto maneja los nombres de archivo con espacios, recursión arbitraria y cualquier número de archivos coincidentes, incluso si exceden el límite de longitud de la línea de comandos.

 8
Author: Idelic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-09 06:07:42

Me gusta usar find y head juntos para "un gato recursivo" en todos los archivos de un directorio de proyecto, por ejemplo:

find . -name "*rb" -print0 | xargs -0 head -10000

La ventaja es que head añadirá su nombre de archivo y ruta:

==> ./recipes/default.rb <==
DOWNLOAD_DIR = '/tmp/downloads'
MYSQL_DOWNLOAD_URL = 'http://cdn.mysql.com/Downloads/MySQL-5.6/mysql-5.6.10-debian6.0-x86_64.deb'
MYSQL_DOWNLOAD_FILE = "#{DOWNLOAD_DIR}/mysql-5.6.10-debian6.0-x86_64.deb"

package "mysql-server-5.5"
...

==> ./templates/default/my.cnf.erb <==
#
# The MySQL database server configuration file.
#
...

==> ./templates/default/mysql56.sh.erb <==
PATH=/opt/mysql/server-5.6/bin:$PATH 

Para el ejemplo completo aquí, por favor vea mi entrada de blog:

Http://haildata.net/2013/04/using-cat-recursively-with-nicely-formatted-output-including-headers/

Tenga en cuenta que usé 'head -10000', claramente si tengo archivos sobre 10.000 líneas esto va a truncar la salida ... sin embargo, podría usar head 100000, pero para "proyecto informal/directorio de navegación" este enfoque funciona muy bien para mí.

 2
Author: Dave Pitts,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-28 11:10:07

Si desea generar solo un recuento total de líneas y no un recuento de líneas para cada archivo algo como:

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

Funciona bien. Esto le ahorra la necesidad de hacer más filtrado de texto en un script.

 1
Author: abalmos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-07 05:29:04
wc -cl `find . -name "*.php" -type f`
 1
Author: PMD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-23 10:32:23

Aquí hay un script Bash que cuenta las líneas de código en un proyecto. Atraviesa un árbol de fuentes recursivamente, y excluye líneas en blanco y 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`
    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

Disfrute! -- Curran

 0
Author: curran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-31 23:58:48
find . -name "*.h" -print | xargs wc -l
 0
Author: SD.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-27 13:02:05