Как посчитать все строки кода в каталоге рекурсивно?


1625

У нас есть приложение PHP, и мы хотим подсчитать все строки кода в определенном каталоге и его подкаталогах. Нам не нужно игнорировать комментарии, так как мы просто пытаемся получить грубое представление.

wc -l *.php 

Эта команда прекрасно работает в данном каталоге, но игнорирует подкаталоги. Я думал, что это может сработать, но возвращается 74, что, безусловно, не так ...

find . -name '*.php' | wc -l

Какой правильный синтаксис для подачи во всех файлах?

Ответы:


2651

Пытаться:

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

Инструмент SLOCCount также может помочь.

Это даст точные исходные строки кода для любой иерархии, на которую вы указываете, а также некоторую дополнительную статистику.

Сортированный вывод:

find . -name '*.php' | xargs wc -l | sort -nr


31
cloc.sourceforge.net, возможно, стоит рассматривать в качестве альтернативы sloccount (больше языков, но меньше информации)
AsTeR

31
с включаемыми файлами также:find . -name '*.php' -o -name '*.inc' | xargs wc -l
rymo

52
Это напечатает больше чем один номер, когда есть много файлов (потому что wcбудет запущен многократно. Также не обрабатывает много специальных имен файлов.
l0b0

42
@idober:find . -name "*.php" -not -path "./tests*" | xargs wc -l
конец

19
Если имя каталога содержит пробелы ... приведенная выше команда не выполняется !!
nitish712

474

Для другого однострочника:

( find ./ -name '*.php' -print0 | xargs -0 cat ) | wc -l

работает с именами с пробелами, выводит только одно число.


1
+1 то же самое ... искали вечно ... все остальные команды "find" возвращали только # фактических файлов .... здесь -print0 получил фактическое количество строк для меня !!! Спасибо!
Ronedog

3
@ TorbenGundtofte-Bruun - смотрите man find.. print0 с xargs -0 позволяет вам работать с файлами, в имени которых есть пробелы или другие странные символы
Shizzmo

2
@ TorbenGundtofte-Bruun - также, -0 в xargs соответствует print0, это своего рода кодирование / декодирование для обработки пробелов.
Тристан Рейд

7
Если вам нужно более одного фильтра имен, я обнаружил, что (по крайней мере с версией find для MSYSGit) вам понадобятся дополнительные ( find . \( -name '*.h' -o -name '*.cpp' \) -print0 | xargs -0 cat ) | wc -l
символы

1
@DesignbyAdrian: ведение журнала помогает в восстановлении после сбоя, а не в скорости. Вероятно, вы видите хорошую производительность из-за кэширования или очень быстрого жесткого диска.
JMH

398

Если вы используете довольно свежую версию Bash (или ZSH), это намного проще:

wc -l **/*.php

В оболочке Bash это требует установки globstarопции, в противном случае **оператор glob не является рекурсивным. Чтобы включить этот параметр, выполните команду

shopt -s globstar

Чтобы сделать это постоянным, добавьте его в один из файлов инициализации ( ~/.bashrcи ~/.bash_profileт. Д.).


7
Я за это проголосую за простоту, однако хочу отметить, что он не ищет рекурсивный поиск в каталогах, он только проверяет подкаталоги текущего каталога. Это на SL6.3.
Годрик Провидец

7
Это зависит от вашей оболочки и опций, которые вы установили. Bash требует, globstarчтобы это работало.
Майкл Уайлд,

2
@PeterSenna, с текущим 3.9.8 архивом ядра, команда wc -l **/*.[ch]находит в общей сложности 15195373 строк. Не уверен, считаете ли вы это «очень низким значением». Опять же, вам нужно убедиться, что вы globstarвключили в Bash. Вы можете проверить с shopt globstar. Чтобы включить это явно, сделайте shopt -s globstar.
Майкл Уайлд

5
@MichaelWild Это хорошее решение, но оно все равно будет переполнено, ARG_MAXесли у вас большое количество .phpфайлов, поскольку wcоно не встроено.
Восстановите Монику, пожалуйста,

1
@AlbertSamuel Нет, вам нужно сравнить список файлов, созданных обоими методами. Мой метод имеет проблему не работать с большим количеством файлов, как упомянуто @BroSlow. Принятый ответ потерпит неудачу, если пути, созданные с помощью findпробелов. Это может быть исправлено с помощью print0и --nullс findи xargsвызовов, соответственно.
Майкл Уайлд

363

Вы можете использовать clocутилиту, которая построена именно для этой цели. Он сообщает каждому количество строк на каждом языке, а также количество комментариев и т. Д. CLOC доступен в Linux, Mac и Windows.

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

$ cloc --exclude-lang=DTD,Lua,make,Python .
    2570 text files.
    2200 unique files.                                          
    8654 files ignored.

http://cloc.sourceforge.net v 1.53  T=8.0 s (202.4 files/s, 99198.6 lines/s)
-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
Javascript                    1506          77848         212000         366495
CSS                             56           9671          20147          87695
HTML                            51           1409            151           7480
XML                              6           3088           1383           6222
-------------------------------------------------------------------------------
SUM:                          1619          92016         233681         467892
-------------------------------------------------------------------------------

4
Это прекрасный инструмент, который работает хорошо и быстро дает полезную статистику в конце. Любить это.
Роб Форрест

4
Обратите внимание, что вы можете запускать команды Unix в Windows, используя cygwin (или другие подобные порты / среды). Для меня такой доступ очень полезен, это необходимость. Командная строка Unix является магическим. Особенно мне нравятся Perl и регулярные выражения.
Кертис Яллоп

CLOC и SLOCCount отлично работают на MacBook середины 2015 года. Обратите внимание, что их числа близки, но не совсем одинаковы для 127k Java проекта Android. Также обратите внимание, что в эквиваленте iOS было 2x LoC; Таким образом, показатель «стоимость» в SLOCCount может быть отключен (или, может быть, iOS разработчик сделает в 2 раза больше, чем разработчик Android. :-)
maxweber

2
Не могли бы вы отредактировать начало этого вопроса, чтобы выяснить, что clocэто кроссплатформенное, поскольку это всего лишь скрипт на Perl?
Кайл Стрэнд

Просто отлично, отлично работает и в Windows bash.
Юриснм

100

В UNIX-подобных системах есть инструмент, clocкоторый предоставляет статистику кода.

Я наткнулся на случайный каталог в нашей кодовой базе:

      59 text files.
      56 unique files.                              
       5 files ignored.

http://cloc.sourceforge.net v 1.53  T=0.5 s (108.0 files/s, 50180.0 lines/s)
-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
C                               36           3060           1431          16359
C/C++ Header                    16            689            393           3032
make                             1             17              9             54
Teamcenter def                   1             10              0             36
-------------------------------------------------------------------------------
SUM:                            54           3776           1833          19481
-------------------------------------------------------------------------------

2
Технически @moose simtao упомянул это как решение для пользователей Windows, не говоря уже о linux или unix.
Тим Сегин

5
@moose Table был отредактирован в его ответе намного позже, чем мой ответ, теперь они действительно выглядят похожими.
Кальмарий

Мне это нравится. Cloc действительно опрятный. Но что означает это имя?
Маноэль Вилела,

Теперь и на Windows! Предполагая, что у вас есть шоколад :choco install cloc
icc97

35

Вы не указали, сколько там файлов или какой желаемый результат. Это то, что вы ищите:

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

2
Это будет работать, если файлов не слишком много: если файлов много, в результате вы получите несколько строк (xargs разделит список файлов на несколько подсписков)
Pascal MARTIN

о да. Вот почему я сказал, что Он не указал, сколько там файлов. Моя версия легче запомнить, но версия Шина лучше, если у вас есть несколько файлов. Я голосую за это.
Павел Полевич

Мне нужно было адаптировать это для использования в функции, где одинарные кавычки слишком ограничены: go () { mkdir /tmp/go; [[ -f ./"$1" ]] && mv ./"$1" /tmp/go; (find ./ -type f -name "$*" -print0 | xargs -0 cat ) | wc -l; wc -l /tmp/go/*; mv /tmp/go/* . } результаты были близки к slocount для *.py, но он не знал *.js, *.html.
Джаланб

31

Еще один вариант :)

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

Изменить: это даст общую сумму, а не файл за файлом.

Edit2: добавить .после, findчтобы заставить его работать


оба ответа суммируют строки.
josh123a123

По крайней мере, в Cygwin у меня были лучшие результаты с:$ find -name \*\.php -print0 | xargs -0 cat | wc -l
Martin Haeberli

на Дарвине это просто дает общую сумму: find . -name '*.php' | xargs cat | wc -l... тогда как это дает файл за файлом и общую сумму:find . -name '*.php' | xargs wc -l
OsamaBinLogin

30

Удивительно, но нет ответа на основании поиска -execи awk. Вот так:

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

Этот фрагмент находит для всех файлов ( -type f). Чтобы найти по расширению файла, используйте -name:

find . -name '*.py' -exec wc -l '{}' \; | awk '{ SUM += $0; } END { print SUM; }'

2
Функционально это работает отлично, но для большого списка (источник linux) это действительно медленно, потому что он запускает wc-процесс для каждого файла вместо 1 wc-процесса для всех файлов. Я рассчитал это на 31 секунду, используя этот метод по сравнению с 1,5 секунд, используя find . -name '*.c' -print0 |xargs -0 wc -l. Тем не менее, этот более быстрый метод (по крайней мере, в OS X) приводит к тому, что выводит «total» несколько раз, поэтому для получения правильного итога требуется дополнительная фильтрация (подробности я опубликовал в своем ответе).
Даг Ричардсон

Это дает преимущество работы с неограниченным количеством файлов. Отлично сработано!
ekscrypto

1
это гораздо лучшее решение, если вы работаете с большим объемом ГБ и файлов. делать wcэто в форме a catмедленно, потому что система должна сначала обработать все ГБ, чтобы начать подсчет строк (протестировано с 200 ГБ jsons, 12k файлов). wcсначала делать, а потом считать результат намного быстрее
ulkas

1
@DougRichardson, вы могли бы рассмотреть это вместо этого: find . -type f -exec wc -l {} \+или find . -name '*.py' -type f -exec wc -l {} \+ который печатает итог в конце вывода. Если все, что вас интересует, это общее количество, то вы можете пойти немного дальше и использовать tail: find . -type f -exec wc -l {} \+ | tail -1илиfind . -name '*.py' -type f -exec wc -l {} \+ | tail -1
JamieJag

25

Более распространенный и простой, как для меня, предположим, что вам нужно подсчитывать файлы с разными расширениями имен (скажем, также нативные)

wc $(find . -type f | egrep "\.(h|c|cpp|php|cc)" )

Спасибо за отзыв, я его исправил.


6
это не совсем то, что вы думаете. найти . -name ' . [am]' идентичен для поиска. -name ' . [a | m]' оба найдут все файлы, заканчивающиеся на .m или
.a

1
но второй также найдет файлы, оканчивающиеся на. | если есть. Таким образом, [h | c | cpp | php | cc] заканчивается тем же, что и [hcp |].
OsamaBinLogin

обратные $()
Сандбург

Это работает под Cygwin. Конечно, диск "C: \" должен соответствовать соглашению Cygwin, например: wc $ (find / cygdrive / c // SomeWindowsFolderj / -type f | egrep "\. (H | c | cpp | php | cc) ")
Кристиан

21

POSIX

В отличие от большинства других ответов здесь, они работают в любой системе POSIX, для любого количества файлов и с любыми именами файлов (кроме отмеченных).


Строки в каждом файле:

find . -name '*.php' -type f -exec wc -l {} \;
# faster, but includes total at end if there are multiple files
find . -name '*.php' -type f -exec wc -l {} +

Строки в каждом файле, отсортированные по пути к файлу

find . -name '*.php' -type f | sort | xargs -L1 wc -l
# for files with spaces or newlines, use the non-standard sort -z
find . -name '*.php' -type f -print0 | sort -z | xargs -0 -L1 wc -l

Строки в каждом файле, отсортированные по убыванию

find . -name '*.php' -type f -exec wc -l {} \; | sort -nr
# faster, but includes total at end if there are multiple files
find . -name '*.php' -type f -exec wc -l {} + | sort -nr

Всего строк во всех файлах

find . -name '*.php' -type f -exec cat {} + | wc -l

19

Есть небольшой инструмент под названием sloccount для подсчета строк кода в каталоге. Следует отметить, что он делает больше, чем вы хотите, поскольку он игнорирует пустые строки / комментарии, группирует результаты по языкам программирования и вычисляет некоторую статистику.


Для окон LocMetrics делает свою работу
Камилла

15

То, что вы хотите, это простой forцикл:

total_count=0
for file in $(find . -name *.php -print)
do
    count=$(wc -l $file)
    let total_count+=count
done
echo "$total_count"

3
разве это не излишество по сравнению с предлагаемыми ответами xargs?
Натан Феллман

5
Нет, Натан. Ответы xargs не обязательно будут печатать счет как одно число. Это может просто напечатать кучу промежуточных итогов.
Роб Кеннеди

3
что будет делать эта программа, если имена файлов содержат пробелы? Как насчет перевода строки? ;-)
Павел Полевич

38
Если имена ваших файлов содержат новые строки, я бы сказал, что у вас есть большие проблемы.
Kzqai

2
@ennuikiller Количество проблем с этим, в первую очередь это сломается на файлах с пробелами. Установка IFS=$'\n'перед циклом, по крайней мере, исправит это для всех, кроме файлов с символами новой строки в их именах. Во-вторых, вы не цитируете '*.php', поэтому он будет расширяться за счет оболочки, а не find, и, следовательно, ergo фактически не найдет ни одного из файлов php в подкаталогах. Также -printявляется избыточным, поскольку подразумевается в отсутствии других действий.
Восстановите Монику, пожалуйста,

12

только для источников:

wc `find`

для фильтрации, просто используйте grep

wc `find | grep .php$`

11

Простой, который будет быстрым, будет использовать всю мощь поиска / фильтрации find, не сбой при слишком большом количестве файлов (переполнение аргументов чисел), отлично работает с файлами со смешными символами в имени, без использования xargsне запустит бесцельно большое количество внешних команд (благодаря +за find«ы -exec). Ну вот:

find . -name '*.php' -type f -exec cat -- {} + | wc -l

2
Я собирался опубликовать вариант этого сам (причем \;вместо того, +что я не знал об этом), этот ответ должен быть правильным ответом.
Марк К Коуэн

7

Я знаю, что вопрос помечен как , но кажется, что проблема, которую вы пытаетесь решить, также связана с PHP.

Себастьян Бергманн написал инструмент под названием PHPLOC, который делает то, что вы хотите, и, кроме того, предоставляет вам обзор сложности проекта. Вот пример его отчета:

Size
  Lines of Code (LOC)                            29047
  Comment Lines of Code (CLOC)                   14022 (48.27%)
  Non-Comment Lines of Code (NCLOC)              15025 (51.73%)
  Logical Lines of Code (LLOC)                    3484 (11.99%)
    Classes                                       3314 (95.12%)
      Average Class Length                          29
      Average Method Length                          4
    Functions                                      153 (4.39%)
      Average Function Length                        1
    Not in classes or functions                     17 (0.49%)

Complexity
  Cyclomatic Complexity / LLOC                    0.51
  Cyclomatic Complexity / Number of Methods       3.37

Как видите, предоставленная информация намного полезнее с точки зрения разработчика, поскольку она может примерно сказать вам, насколько сложен проект, прежде чем вы начнете работать с ним.


7

Полагаю, никто никогда не увидит, что это закопано сзади ... И все же ни один из ответов до сих пор не касается проблемы имен файлов с пробелами. Кроме того, все, что используется xargs, может потерпеть неудачу, если общая длина путей в дереве превышает предельный размер среды оболочки (по умолчанию - несколько мегабайт в Linux). Вот тот, который решает эти проблемы довольно прямо. Подоболочка заботится о файлах с пробелами. awkСоставляет поток отдельных файлов wcвыходов, поэтому никогда не должен бежать из космоса. Он также ограничивает execтолько файлы (пропуская каталоги):

find . -type f -name '*.php' -exec bash -c 'wc -l "$0"' {} \; | awk '{s+=$1} END {print s}' 

6

WC -L? лучше использовать GREP -C ^

wc -l? Неправильно! Команда wc считает коды новых строк, а не строк! Если последняя строка в файле не заканчивается кодом новой строки, это не засчитывается!

если вы все еще хотите считать строки, используйте grep -c ^ , полный пример:

#this example prints line count for all found files
total=0
find /path -type f -name "*.php" | while read FILE; do
     #you see use grep instead wc ! for properly counting
     count=$(grep -c ^ < "$FILE")
     echo "$FILE has $count lines"
     let total=total+count #in bash, you can convert this for another shell
done
echo TOTAL LINES COUNTED:  $total

наконец, следите за ловушкой wc -l (число вводов, а не строк !!!)


Пожалуйста, прочтите POSIX-определение строки . При grep -c ^подсчете количества неполных строк такие неполные строки не могут появиться в текстовом файле .
gniourf_gniourf

2
Я знаю это. На практике только последняя строка может быть неполной, потому что у нее нет EOL. Идея заключается в подсчете всех строк, включая неполную. Это очень частая ошибка, считая только полные строки. после подсчета мы думаем "почему я пропустил последнюю строчку ???". Это ответ почему, и рецепт, как это сделать правильно.
Зник

Или, если вы хотите один вкладыш: find -type f -name '*.php' -print0 | xargs -0 grep -ch ^ | paste -sd+ - | bc см. Здесь для альтернативы bc: stackoverflow.com/q/926069/2400328
techniao

4

очень просто

find /path -type f -name "*.php" | while read FILE
do
    count=$(wc -l < $FILE)
    echo "$FILE has $count lines"
done

1
он потерпит неудачу, если в одном из имен файлов будет пробел или
символ

4

Если вы хотите, чтобы результаты сортировались по количеству строк, вы можете просто добавить | sortили | sort -r( -rв порядке убывания) к первому ответу, например так:

find . -name '*.php' | xargs wc -l | sort -r

1
Так как вывод xargs wc -lявляется числовым, на самом деле нужно будет использовать sort -nили sort -nr.
Дастин Ингрэм

4

Для Windows простым и быстрым инструментом является LocMetrics .


Весьма маловероятно, что OP используется в Windows, если они используют bash.

1
Заголовок и описание вопроса @VanessaMcHale явно не требуют решения только для Unix. Таким образом, решение на основе Windows является приемлемым. Также Google указал мне на эту страницу, когда я искал подобное решение.
Walv

Этот комментарий помог мне. Я попробовал это, и это работает хорошо.
Аллан Ф

4

Что-то другое:

wc -l `tree -if --noreport | grep -e'\.php$'`

Это работает нормально, но вам нужно иметь хотя бы один *.phpфайл в текущей папке или в одной из ее подпапок, иначе он wcостановится


может также переполниться ARG_MAX
Марк К Коуэн

4

Если вы работаете в Linux (и я так понимаю), я рекомендую мой инструмент polyglot . Это значительно быстрее, чем либо, sloccountлибо clocболее функционально, чем sloccount.

Вы можете вызвать его с

poly .

или

poly

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


4

С zsh globs это очень просто:

wc -l ./**/*.php

Если вы используете Bash, вам просто нужно обновить. Нет абсолютно никаких причин использовать bash.


4

Инструмент Tokei отображает статистику о коде в каталоге. Tokei покажет количество файлов, общее количество строк в этих файлах и код, комментарии и пробелы, сгруппированные по языку. Tokei также доступен на Mac, Linux и Windows.

Пример вывода Tokei выглядит следующим образом:

$ tokei
-------------------------------------------------------------------------------
 Language            Files        Lines         Code     Comments       Blanks
-------------------------------------------------------------------------------
 CSS                     2           12           12            0            0
 JavaScript              1          435          404            0           31
 JSON                    3          178          178            0            0
 Markdown                1            9            9            0            0
 Rust                   10          408          259           84           65
 TOML                    3           69           41           17           11
 YAML                    1           30           25            0            5
-------------------------------------------------------------------------------
 Total                  21         1141          928          101          112
-------------------------------------------------------------------------------

Tokei можно установить, следуя инструкциям в файле README в хранилище .


1
Это должен быть принятый ответ
Илия

3

Если вам нужно только общее количество строк, скажем, в ваших PHP-файлах, вы можете использовать очень простую однострочную команду даже под Windows, если у вас установлен GnuWin32. Нравится:

cat `/gnuwin32/bin/find.exe . -name *.php` | wc -l

Вам необходимо указать, где именно находится find.exe, иначе будет предоставлен Windows FIND.EXE (из старых DOS-подобных команд), поскольку он, вероятно, находится перед GnuWin32 в среде PATH и имеет другие параметры и результаты.

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


В приведенном выше примере я использую bash для Windows вместо cmd.exe, поэтому есть прямые косые черты "/", а не обратные косые черты "\".
Невен Боянов

3

Сначала выдает самые длинные файлы (т. Е. Может быть, эти длинные файлы нуждаются в некотором рефакторинге?), Исключая некоторые каталоги поставщиков:

 find . -name '*.php' | xargs wc -l | sort -nr | egrep -v "libs|tmp|tests|vendor" | less

3

Если вы хотите сохранить простоту, вырежьте посредника и просто позвоните wcсо всеми именами файлов:

wc -l `find . -name "*.php"`

Или в современном синтаксисе:

wc -l $(find . -name "*.php")

Работает, пока нет пробелов ни в одном из имен каталогов или имен файлов. И пока у вас нет десятков тысяч файлов (современные оболочки поддерживают действительно длинные командные строки). В вашем проекте 74 файла, так что у вас достаточно места для роста.


Мне нравится этот! Если вы находитесь в гибридной среде C / C ++:wc -l `find . -type f \( -name "*.cpp" -o -name "*.c" -o -name "*.h" \) -print`
Брэм,

был удивлен, что это был не самый лучший ответ
ms4720

3

Вам не нужны все эти сложные и трудно запоминающиеся команды. Вам просто нужен инструмент под названием line-counter .

Краткий обзор

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

$ pip install line-counter

Используйте lineкоманду, чтобы получить количество файлов и количество строк в текущем каталоге (рекурсивно)

$ line
Search in /Users/Morgan/Documents/Example/
file count: 4
line count: 839

Если вы хотите больше деталей, просто используйте line -d.

$ line -d
Search in /Users/Morgan/Documents/Example/
Dir A/file C.c                                             72
Dir A/file D.py                                           268
file A.py                                                 467
file B.c                                                   32
file count: 4
line count: 839

И лучшая часть этого инструмента, вы можете добавить .gitignoreкак настроить файл к нему. Вы можете настроить правила, чтобы выбирать или игнорировать, какие типы файлов считать так же, как в «.gitignore».

Более подробное описание и использование здесь: https://github.com/MorganZhang100/line-counter


3

Если файлов слишком много, лучше просто посмотреть общее количество строк.

find . -name '*.php' | xargs wc -l | grep -i ' total' | awk '{print $1}'

2

По крайней мере, в OS X команды find + xarg + wc, перечисленные в некоторых других ответах, печатают «total» несколько раз в больших списках, и полная сумма не указывается. Мне удалось получить единый итог для файлов .c с помощью следующей команды:

find . -name '*.c' -print0 |xargs -0 wc -l|grep -v total|awk '{ sum += $1; } END { print "SUM: " sum; }'

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.