Tengo un montón de archivos de código que he seleccionado con un comando de find .
Necesito contar líneas de código pero filtrar líneas que no me interesan, es decir, todas las declaraciones de import .
¿Cómo puedo hacer esto en bash?
Esto es lo que tengo hasta ahora:
function codecount { find . -name "$@" | grep -v test | xargs wc -l; } Entonces, si ejecuto codecount *.java , encontrará todos mis archivos Java, eliminando cualquiera que sea código de prueba, luego cuente las líneas. Quiero refinar aún más esto para filtrar las líneas de "importación" en los archivos restantes antes del recuento de líneas.
En Bash, puede usar globstar junto con extglob :
shopt -s extglob shopt -s globstar codecount() { grep -v ^import **/!(test*).java | wc -l }Explicación:
grep -v ^import <file-list> imprime todas las líneas de <file-list> excepto aquellas que comienzan con import . **/!(test*).java se puede descomponer en tres partes:
** se usa para hacer coincidir todos los archivos en el directorio actual y en los subdirectorios;!(test*) significa: todo excepto los archivos que comienzan con test ;.java : todo lo que termina en .java Entonces, al final, coincidirá con todos los archivos de Java excepto aquellos que comiencen con test .
wc -l cuenta líneas.Tenga en cuenta que también cuenta las líneas en blanco. Si desea excluir líneas en blanco, utilice:
grep -v -e "^import" -e "^$" **/!(test*).java | wc -lSugiero considerar usar ag en lugar de grep .
Está creado para este uso y es más rápido que grep, ya que ignora automáticamente los archivos binarios y las carpetas .git , etc. También tiene muchas opciones adicionales útiles.
Enumere las rutas de archivo con importación y el recuento de líneas coincidentes en cada archivo
ag import --java --countResumen detallado
ag import --java --statsPor supuesto, también puede buscar por expresiones regulares. Creo que esto le dará el resultado que está buscando, al usar invert-match para mostrar solo las líneas que no coinciden, y nogroup para no agregar espacios y encabezados para cada archivo.
ag '(^import|test)' --invert-match --java --nogroup | wc -lEs casi posible usando solo grep:
grep -r --include='*.java' --exclude='*test*' -vch '^import' *Esto hace lo siguiente:
-r : busca recursivamente en todos los subdirectorios--include='*.java' : solo archivos grep que terminan en .java--exclude-'*test*' : ... pero excluye archivos donde el nombre contiene test-v '^import' : invertir coincidencia, excluir líneas que comienzan con import-c : cuenta las coincidencias en lugar de devolverlas (cuenta por línea)-h : suprime la salida de nombres de archivo, solo imprime el número de coincidenciasEsto devuelve algo como
2 3 5 y solo queremos el total. En lugar de canalizar a | paste -s -d '+' | bc antes de | paste -s -d '+' | bc o incluso | awk '{sum += $1} END { print sum }' , podemos retroceder un paso, imprimir las líneas coincidentes y luego contarlas con wc :
grep -r --include='*.java' --exclude='*test*' -vh '^import' * | wc -lEsto se puede convertir en una función donde el parámetro determina qué debe incluirse, solo debemos tener cuidado con las comillas:
codecount () { grep -r --include="$1" --exclude='*test*' -vh '^import' * | wc -l }esto tiene que llamarse asi
codecount '*.java' para evitar la expansión del * antes de ser utilizado en la función.
Cambio mínimo en la solución de OP:
Si realmente desea utilizar find , grep y xargs , puede modificar su intento de esta manera:
codecount () { find . -name "$@" | grep -v test | xargs grep -v '^import' | wc -l } Acabo de agregar un paso grep -v para filtrar líneas que comienzan con import (y reemplacé function codecount con codecount () para mejorar la portabilidad).
Tenga en cuenta que esto aún debe llamarse con comillas en la línea de comando:
codecount '*.java' find -exec cat y grep :
Una última solución: usar find para filtrar los nombres de archivo que contienen test en lugar de xargs grep -v , luego cat para que grep no vea los nombres de archivo:
find -type f -name '*.java' -not -name '*test*' -exec cat {} \; | grep -vc '^import'Esto se puede convertir en una función al igual que los otros dos ejemplos, y el comentario entre comillas aún se aplica.