Как подсчитать строки кода, включая подкаталоги
Предположим, что я хочу подсчитать строки кода в проекте. Если все файлы находятся в одном каталоге, я могу выполнить:
cat * | wc -l
Однако, если есть подкаталоги, это не сработает. Для этого для работы кот должен иметь рекурсивный режим. Я подозреваю, что это может быть работа для xargs, но мне интересно, есть ли более элегантное решение?
Ответы
Ответ 1
Сначала вам не нужно использовать cat
для подсчета строк. Это антипаттерн, называемый бесполезным использованием Cat (UUoC). Чтобы подсчитать строки в файлах в текущем каталоге, используйте wc
:
wc -l *
Затем команда find
перезаписывает подкаталоги:
find . -name "*.c" -exec wc -l {} \;
-
.
- это имя верхнего каталога для начала поиска из
-
-name "*.c"
- это шаблон интересующего вас файла
-
-exec
дает команду для выполнения
-
{}
является результатом команды find, которая должна быть передана команде (здесь wc-l
)
-
\;
указывает конец команды
Эта команда создает список всех файлов, найденных с их количеством строк, если вы хотите получить сумму для all найденных файлов, вы можете использовать find для перечисления файлов (с помощью -print
), а затем использовать xargs для передачи этого списка в качестве аргумента в wc-l.
find . -name "*.c" -print | xargs wc -l
EDIT для ответа на комментарий Роберта Гэмбла (спасибо): если в именах файлов есть пробелы или новые строки (!), то вместо -print
и xargs -null
вы должны использовать опцию -print0
, чтобы список файлов имена заменяются нулевыми символами.
find . -name "*.c" -print0 | xargs -0 wc -l
В философии Unix есть инструменты, которые делают только одну вещь, и делают это хорошо.
Ответ 2
Если вам нужен ответ на игру с кодом:
grep '' -R . | wc -l
Проблема с просто использованием wc -l сама по себе заключается в том, что он не подходит хорошо, а oneliners, использующие
find . -exec wc -l {} \;
Не даст вам общий счет строки, потому что он запускает wc один раз для каждого файла (loL!)
и
find . -exec wc -l {} +
Будет запутано, как только поиск попадет в ~ 200k 1 , 2 ограничение символьного параметра для параметров и вместо этого вызывает wc несколько раз, каждый раз только предоставляя вам частичное резюме.
Кроме того, вышеупомянутый трюк grep не будет добавлять более 1 строки к выходу, когда он встретит двоичный файл, что может быть косвенно полезным.
За 1 дополнительный командный символ вы можете полностью игнорировать двоичные файлы:
grep '' -IR . | wc -l
Если вы хотите также запустить подсчет строк в двоичных файлах
grep '' -aR . | wc -l
Сноска о границах:
Документы немного расплывчаты относительно того, ограничено ли ограничение размера строки или количество токенов.
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
Это подразумевает, что он будет очень легко загружаться.
Ответ 3
Я думаю, что вы, вероятно, застряли в xargs
find -name '*php' | xargs cat | wc -l
chromakode дает тот же результат, но намного медленнее. Если вы используете xargs, ваше катирование и наложение могут начинаться, как только поиск начинает находить.
Хорошее объяснение в Linux: xargs vs. exec {}
Ответ 4
Попробуйте использовать команду find
, которая по умолчанию рекурсирует каталоги:
find . -type f -execdir cat {} \; | wc -l
Ответ 5
Правильный способ:
find . -name "*.c" -print0 | xargs -0 cat | wc -l
Вы должны использовать -print0, потому что в именах Unix есть только два недопустимых символа: нулевой байт и "/" (косая черта). Так, например, "xxx\npasswd" является допустимым именем. В действительности, вы, скорее всего, столкнетесь с именами с пробелами в них. Приведенные выше команды будут считать каждое слово отдельным файлом.
Вы также можете использовать "-type f" вместо имени для ограничения поиска файлов.
Ответ 6
Использование cat или grep в вышеприведенных решениях является расточительным, если вы можете использовать относительно недавние инструменты GNU, включая Bash:
wc -l --files0-from=<(find . -name \*.c -print0)
Это обрабатывает имена файлов с пробелами, произвольной рекурсией и любым количеством совпадающих файлов, даже если они превышают ограничение длины командной строки.
Ответ 7
Мне нравится использовать find и head вместе для "рекурсивного кота" для всех файлов в каталоге проекта, например:
find . -name "*rb" -print0 | xargs -0 head -10000
Преимущество заключается в том, что голова добавит ваше имя файла и путь:
==> ./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
Для полного примера здесь, пожалуйста, см. мое сообщение в блоге:
http://haildata.net/2013/04/using-cat-recursively-with-nicely-formatted-output-including-headers/
Примечание. Я использовал "head -10000", очевидно, если у меня есть файлы более 10 000 строк, это приведет к усечению вывода... однако я мог бы использовать head 100000, но для "неформального просмотра проектов/каталогов" этот подход работает очень хорошо для меня.
Ответ 8
Если вы хотите сгенерировать только общее количество строк, а не количество строк для каждого файла, что-то вроде:
find . -type f -exec wc -l {} \; | awk '{total += $1} END{print total}'
работает хорошо. Это избавит вас от необходимости выполнять дополнительную фильтрацию текста в script.
Ответ 9
wc -cl `find . -name "*.php" -type f`
Ответ 10
Здесь Bash script, который подсчитывает строки кода в проекте. Он рекурсивно пересекает исходное дерево и исключает пустые строки и одиночные комментарии, которые используют "//".
# $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
Вот как выглядит вывод для моего проекта:
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
Наслаждайтесь! - Curran
Ответ 11
find . -name "*.h" -print | xargs wc -l