количество (непустых) строк кода в bash


151

В Bash как подсчитать количество непустых строк кода в проекте?


1
Многие из приведенных ниже решений работают только для одного файла (например foo.c). Любые мысли о количестве строк в проекте (например, много файлов в структуре каталогов, и исключая двоичные файлы)?
разгадывание головоломок

5
@solvingPuzzles Я думаю, что могу ответить на эту часть. Для любого решения, которое работает с одним файлом, например «cat FILE | sed blah», вы можете работать со многими файлами, заменив «cat FILE» командой, в которой перечислены имена файлов, с которыми нужно работать, например, «find. -Name» * .py '", и отправьте это в" xargs cat ". например, "find. -name '* .py' | xargs cat | sed '/ ^ \ s * $ / d' | wc -l"
Джонатан Хартли

2
@JonathanHartley @solvingPuzzles также есть подобные программы, slocи clocони здесь для подсчета количества строк кода.
AsTeR

OP здесь: Когда я впервые задал эту проблему, cloc не очень хорошо справился с Python-кодом. В наше время это здорово.
Джонатан Хартли,

Cloc также доступен в виде модуля npm и экономит много времени.
Кришна Ведула

Ответы:


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

И если вы считаете комментарии пустыми строками:

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

Хотя это зависит от языка.


24
Не уверен, почему вы используете кошку там. Используйте foo.c или foo.pl в качестве имени файла для передачи в sed. sed '/ ^ \ s * $ / d' foo.c | wc -l
Энди Лестер

28
Просто привычка. Я читаю конвейеры слева направо, что означает, что я обычно начинаю с cat, затем action, action, action и т. Д. Очевидно, конечный результат один и тот же.
Майкл Крамер

32
Чтобы сделать это для всех файлов во всех подпапках и исключить комментарии с помощью «//», расширьте эту команду следующим образом: find. -type f -name '* .c' -exec cat {} \; | sed '/ ^ \ s * # / d; / ^ \ s * $ / d; / ^ \ s * \ / \ // d' | wc -l
Бенджамин Интал

11
Вы можете читать слева направо без UUOC: < foo.pl sed 'stuff' | wc -l.
jw013

22
Вообще говоря, UUOC не важен, но удобочитаемость есть.
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

Выше приведено общее количество строк кода (пустые строки удалены) для проекта (текущая папка и все подпапки рекурсивно).

В приведенных выше "./blog" "./punbb" "./js/3rdparty" и "./pma" находятся папки, которые я в черном списке, так как я не написал в них код. Также .php, .as, .sql, .css, .js являются расширениями просматриваемых файлов. Любые файлы с другим расширением игнорируются.


1
вариант для приложения Rails: найти. -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' | кот xargs | sed '/ ^ \ s * $ / d' | wc -l
poseid

1
Вам нужно добавить $в grep ( ...\.js$|...), иначе он будет совпадать feature.js.swp.
Xeoncross

Вы забыли привязку, поэтому она содержит неправильные файлы. И еще более простая версия с привязкой:find . | egrep '.\.c$|.\.h$' | xargs cat | sed '/^\s*$/d' | wc -l
Mark Jeronimus

36

Если вы хотите использовать что-то кроме сценария оболочки, попробуйте CLOC :

cloc считает пустые строки, строки комментариев и физические строки исходного кода во многих языках программирования. Он полностью написан на Perl без каких-либо зависимостей вне стандартного дистрибутива Perl v5.6 и выше (код из некоторых внешних модулей встроен в cloc) и поэтому довольно переносим.


2
Когда я впервые задал этот вопрос, 'cloc' считал строки документации Python как строки кода, что было неоптимальным ИМХО. Современные версии 'cloc' теперь считают строки документации Python комментариями, которые мне нравятся гораздо больше.
Джонатан Хартли

Это правильный ответ! Я только что попробовал cloc out, и он хорошо справляется со своей задачей.
LeeMobile

31

Есть много способов сделать это, используя обычные утилиты оболочки.

Мое решение:

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

При этом выполняется поиск строк в <file> не совпадающих (-v) строках, которые соответствуют шаблону (-e) '^ \ s * $', который является началом строки, за которой следуют 0 или более пробельных символов, а затем к концу строки (т. е. нет содержимого, отличного от пробела), и отобразите количество совпадающих строк (-c) вместо самих совпадающих строк.

Преимущество этого метода перед методами, которые включают в себя конвейерную передачу wc, состоит в том, что вы можете указать несколько файлов и получить отдельный счетчик для каждого файла:

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

config.hh:36
exceptions.hh:48
layer.hh:52
main.hh:39

2
Спасибо! Между прочим, wc предоставляет счетчик для каждого данного файла плюс итоговое значение.
Джонатан Хартли

1
Не, если вы в нее ввязываетесь, хотя по стандарту считается только один файл.
SpoonMeiser

Это лучший ответ на мой взгляд.
simhumileco

-eне обязательно. Это нормальное позиционное расположение паттерна, и вы не делаете с ним ничего прикольного. Но нет ничего плохого в том, чтобы быть явным, если это твой стиль.
Джектоз

13

'wc' считает строки, слова, символы, поэтому для подсчета всех строк (включая пустые) используйте:

wc *.py

Чтобы отфильтровать пустые строки, вы можете использовать grep:

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

«-v» указывает grep выводить все строки, кроме тех, которые соответствуют «^» - начало строки. «\ s *» - ноль или более пробельных символов. «$» - конец строки * .py - мой пример для все файлы, которые вы хотите посчитать (все файлы Python в текущем каталоге), выводятся в канал wc. Пошли.

Я отвечаю на свой (настоящий) вопрос. Не удалось найти запись переполнения стека, покрывающую это.


5
\ W не соответствует пробелу, оно соответствует несловесным символам. Это противоположность \ w, слово символов. \ W Будет соответствовать всему, что не является буквенно-цифровым или подчеркиванием, и, следовательно, не будет делать то, что вы утверждаете здесь. Вы имеете в виду \ s
SpoonMeiser

9

Эта команда подсчитывает количество непустых строк.
cat fileName | grep -v ^$ | wc -l
grep -v ^ $ функция регулярного выражения игнорирует пустые строки.


Этот ответ является самым простым
samthebest

2
В catэтой цепочке нет необходимости :grep -v ^$ fileName | wl -l
Эталиды

7
В этом нет необходимости, wc -lпотому что у grep -c:grep -vc ^$ fileName
Jacktose


5
cat 'filename' | grep '[^ ]' | wc -l

должен сделать трюк просто отлично


3
Зачем использовать cat и направлять файл в grep, если вы можете передать имя файла в качестве аргумента для grep?
SpoonMeiser

правда, это просто старый псевдоним, который у меня есть ... он делает то же самое, что и ваше решение, вместо использования обратного
curtisk

4
awk '/^[[:space:]]*$/ {++x} END {print x}' "$testfile"

1
Я бы проголосовал за это только потому, что я буквально никогда не видел, чтобы кто-то использовал преинкремент в скрипте awk, но, к сожалению, это учитывает только пустые строки. :) Вы имеете в виду awk '!/^[[:space:]]*$/{++x} END{print x}'. Или, если вы действительно ненавидите негативы awk '{y++} /^[[:space:]]*$/{++x} END{print y-x}'
,;

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

Я отправляю это, потому что другие варианты дали неправильные ответы для меня. Это работало с моим источником Java, где строки комментариев начинаются с / или * (я использую * в каждой строке в многострочном комментарии).


Это работоспособное решение. Единственное, на что следует обратить внимание: многострочные комментарии не учитываются
Amol

2

Вот скрипт Bash, который считает строки кода в проекте. Он рекурсивно просматривает исходное дерево и исключает пустые строки и однострочные комментарии, которые используют «//».

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

Вот как выглядит вывод для моего проекта :

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

Наслаждайтесь! - Курран


1

Это будет зависеть от количества файлов в вашем проекте. В теории вы могли бы использовать

grep -c '.' <list of files>

Где вы можете заполнить список файлов с помощью утилиты поиска.

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

Даст вам количество строк на файл.


1
, соответствует пробелу. Это решение работает только в том случае, если вы считаете, что строка, содержащая только пробел, является непустой, что технически так, хотя, вероятно, это не то, что вам нужно.
SpoonMeiser

1

Скрипт для рекурсивного подсчета всех непустых строк с определенным расширением файла в текущем каталоге:

#!/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;

Пример использования:

./countlines.sh .py .java .html

Спасибо @Andy Lester (+1 за ваш комментарий) за «непустую» часть рецепта.
Кит Пинсон

Спасибо также @Michael Cramer (+1 за ваше сообщение) за первоначальную публикацию (чуть более многословного) "непустого" решения.
Кит Пинсон

1

Если вы хотите получить сумму всех непустых строк для всех файлов с заданным расширением во всем проекте:

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

Первый аргумент - это базовый каталог проекта, второй - расширение файла. Пример использования:

./scriptname ~/Dropbox/project/src java

Это немного больше, чем коллекция предыдущих решений.


Этот получает награду за наибольшее количество вызовов fork + exec, запуская grep один раз в строке в каждом файле. ;)
dannysauer

0
grep -v '^\W*$' `find -type f` | grep -c '.' > /path/to/lineCountFile.txt

дает общее количество для всех файлов в текущем каталоге и его подкаталогах.

НТН!


\ W - это несимвольные символы; это не будет соответствовать линии, как ${-[*]} + $@, например. Который, безусловно, действительный код где-то в мире. ;) Вы имеете в виду \ s для космоса.
dannysauer

0

Это дает количество строк без учета пустых строк:

grep -v ^$ filename wc -l | sed -e 's/ //g' 


-3

Для этого в Linux уже есть программа под названием 'wc'.

Просто

wc -l *.c 

и это дает вам общее количество строк и строк для каждого файла.


3
Привет. «wc» сам по себе не ищет подкаталоги и не отфильтровывает пустые строки, оба явно заданы в вопросе.
Джонатан Хартли

wcсчитает пустые строки. ОП хочет подсчитать непустые строки. Это правда, что он захочет использоватьwc , но только после того, как он будет отредактирован потоком с помощьюsed
EhevuTov
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.