Считать строки кода?

24

если я хочу посчитать строки кода, тривиальная вещь

cat *.c *.h | wc -l

Но что, если у меня есть несколько подкаталогов?

Никлас
источник
3
Не по теме: зачем ненужное cat? wc -l *.c *.hделает то же самое.
Томас Падрон-Маккарти
5
@ ThomasPadron-McCarthy Нет, это не так. Вам нужно wc -l *.c *.h | tail -n 1получить аналогичный вывод.
Жиль "ТАК ... перестать быть злым"
2
Обратите внимание, что некоторые (возможно, даже большинство) современных оболочек (Bash v4, Zsh, возможно, больше) предоставляют рекурсивно-глобальный механизм использования **, так что вы могли бы использовать wc -l **/*.{h,c}или что-то подобное. Обратите внимание, что в Bash, по крайней мере, эта опция ( по умолчанию globstar) отключена по умолчанию. Но также учтите, что в данном конкретном случае это clocили SLOCCountгораздо лучший вариант. (Кроме того, ackможет быть предпочтительнее, чтобы findлегко находить / выводить список исходных файлов.)
Кайл Стрэнд,
5
wc -l считает строки, а не строки кода. 7000 пустых строк по-прежнему будут отображаться в wc -l, но не будут учитываться в метрике кода. (комментарии тоже обычно не учитываются)
coteyr

Ответы:

49

Самый простой способ - использовать инструмент под названием cloc. Используйте это так:

cloc .

Вот и все. :-)

HO1
источник
1
-1 потому что эта программа не имеет возможности распознавать строки кода на языках за пределами своего маленького, скучного мозга. Он знает об Ada и Pascal, а также C и C ++, Java и JavaScript, а также о языках «корпоративного» типа, но он отказывается считать SLOC только по расширению файла и, таким образом, совершенно бесполезен для DSL или даже языков, которых он просто не знает. около.
кот
21
@cat Ничто не идеально, и ничто не может удовлетворить все ваши прошлые и будущие требования.
Ho1
2
Что ж, язык программирования, который CLOC отказывается признавать, действительно отвечает всем моим прошлым и будущим требованиям :)
cat
6
@cat согласно документации CLOC, которую он может прочитать в файле определения языка, поэтому есть способ заставить его распознавать код на языках, которые он не определил. Кроме того, это открытый исходный код, поэтому вы всегда можете расширить его, чтобы сделать его лучше!
Сентиман
39

Вам, вероятно, следует использовать для этого SLOCCount или cloc , они предназначены специально для подсчета строк исходного кода в проекте, независимо от структуры каталогов и т. Д .; или

sloccount .

или

cloc .

создаст отчет по всему исходному коду, начиная с текущего каталога.

Если вы хотите использовать findи wc, у GNU wcесть хорошая --files0-fromопция:

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

(Спасибо SnakeDoc за предложение !)

Стивен Китт
источник
+1 за отклик. Интересно, что запуск sloccount /tmp/stackexchange(созданный заново 17 мая после моей последней перезагрузки) говорит, что ориентировочная стоимость разработки найденных им файлов sh, perl, awk и т. Д. Составляет 11 029 долларов. и это не включает в себя однострочники, которые никогда не превращались в файл сценария.
Cas
11
Оценка стоимости на основе строк кода? А как насчет всех людей, занятых переработкой спагетти во что-то обслуживаемое?
Стоп Harm Monica
@OrangeDog вы всегда можете попытаться объяснить это в накладных расходах; см. документацию для объяснения расчета (с очень старыми данными о зарплате) и параметров, которые вы можете настроить.
Стивен Китт
5
clocтоже хорошо: github.com/AlDanial/cloc
SnakeDoc
@StephenKitt> Тем не менее, главная проблема - это обратный отсчет. При очистке кода вы часто получаете меньше строк. Конечно, вы можете попытаться уменьшить накладные расходы на оставшуюся часть кода, чтобы учесть удаленный код, но я не понимаю, как это лучше, чем просто угадывать всю цену в первую очередь.
спектры
10

Поскольку wcкоманда может принимать несколько аргументов, вы можете просто передать все имена файлов, wcиспользуя +аргумент -execдействия GNU find:

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

Альтернативно, bashиспользуя опцию shell globstarдля рекурсивного обхода каталогов:

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

Другие оболочки по умолчанию рекурсивно (например zsh) или имеют аналогичные опции, как globstar, по крайней мере, большинство из них.

heemayl
источник
1
+1 за то, что не нужно устанавливать нестандартное программное обеспечение на машину, где у меня нет root
Bamboomy
5

Вы можете использовать findвместе с xargsи wc:

find . -type f -name '*.h' -o -name '*.c' | xargs wc -l
coffeMug
источник
2
(при этом предполагается, что пути к файлам не содержат пробелов, символов новой строки, одинарных кавычек, двойных кавычек символов обратной косой черты. Может также выводиться несколько totalстрок, если wcвызывается несколько s.)
Стефан Шазелас
Возможно несколько wcпроблем команд могут быть решены с помощью трубопровода findк while read FILENAME; do . . .doneструктуре. И внутри цикла использования цикла wc -l. Остальное суммирует все строки в переменную и отображает ее.
Сергей Колодяжный
5

Если вы находитесь в среде, где у вас нет доступа и clocт.д., я бы предложил

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

Прогон: findпоиск рекурсивно для всех обычных файлов, имя которых заканчивается в любом .cили .hи работает catна них. Выходные данные передаются по конвейеру grepдля подсчета всех непустых строк (тех, которые содержат хотя бы один непробельный символ).

Котте
источник
4

Как было отмечено в комментариях, cat file | wc -lэто не эквивалентно, wc -l fileпотому что первый печатает только число, а второй печатает число и имя файла. Аналогично cat * | wc -lбудет напечатано только число, тогда как wc -l *напечатает строку информации для каждого файла.

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

если я хочу посчитать строки кода, тривиальная вещь

cat *.c *.h | wc -l

Но что, если у меня есть несколько подкаталогов?

Во-первых, вы можете упростить даже свою тривиальную команду:

cat *.[ch] | wc -l

И, наконец, эквивалент многих подкаталогов:

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

Возможно, это можно улучшить многими способами, например, ограничив сопоставляемые файлы только обычными файлами (не каталогами), добавив -type f- но данная findкоманда является точным рекурсивным эквивалентом cat *.[ch].

Wildcard
источник
3

Образец с использованием awk:

find . -name '*.[ch]' -exec wc -l {} \; |
  awk '{SUM+=$1}; END { print "Total number of lines: " SUM }'
Ламберт
источник
Используйте +вместо \;.
Джонатан Леффлер
@JonathanLeffler Почему?
Хастур
1
@Hastur: Он работает wc -lдля групп файлов, а как xargsделает, но он обрабатывает нечетные шариковые символы (например , пробела) в именах файлов без необходимости либо xargsили (нестандартная) -print0и -0опции к findи xargsсоответственно. Это небольшая оптимизация. Недостатком было бы то, что каждый вызов выводил wcбы общее количество строк в конце, если дано несколько файлов - awkсценарий справился бы с этим. Таким образом, это не слэм-данк, но очень часто, используя +вместо \;с findхорошей идеей.
Джонатан Леффлер
@JonathanLeffler Спасибо. Я согласен. Однако мои опасения были связаны с длиной строки параметров, передаваемой в wc. Если априори неизвестно количество файлов, которые будут найдены , есть ли риск преодолеть этот лимит или каким-то образом это обрабатывается командой find?
Хастур
2
@Hastur: findгруппирует файлы в пакеты подходящего размера, которые не будут превышать ограничение длины для списка аргументов на платформе, учитывая среду (которая определяется длиной списка аргументов - так что длина списка аргументов плюс длина среды должна быть меньше максимальной величины). IOW, findделает работу правильно, как xargsделает работу правильно.
Джонатан Леффлер
1

легкая команда:

find . -name '*.[ch]' | xargs wc -l
Malyy
источник
(при этом предполагается, что пути к файлам не содержат пробелов, символов новой строки, одинарных кавычек, двойных кавычек символов обратной косой черты. Может также выводиться несколько totalстрок, если wcвызывается несколько s.)
Стефан Шазелас
0

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

Вы также должны иметь возможность использовать BSD, хотя двоичных файлов не предусмотрено.

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

poly .

источник
-2

find . -name \*.[ch] -print | xargs -n 1 wc -lдолжен сделать свое дело. Существует также несколько возможных вариантов, например, использование -execвместо передачи вывода в wc.

Джон
источник
4
Но find . -name \*.[ch] -printне печатает содержимое файлов, только имена файлов. Поэтому я считаю количество файлов, не так ли? Нужно ли мне xargs?
Никлас
@ Programmer400 да, вам нужно xargs, и вам также нужно следить за несколькими wcвызовами, если у вас много файлов; вам нужно искать все totalстроки и суммировать их.
Стивен Китт
Если вы просто хотите общее количество строк, вам нужно сделатьfind . -name \*.[ch] -print0 | xargs -0 cat | wc -l
пушистый
Обратите внимание, что this ( find . -name \*.[ch] -print | wc -l) считает количество файлов (если имя файла не содержит символ новой строки - но это очень необычно) - оно не учитывает количество строк в файлах.
Джонатан Леффлер