Как подсчитать строки кода, включая подкаталоги [duplicate]

этот вопрос уже есть ответ здесь:

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

cat * | wc -l

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

11 ответов


сначала вам не нужно использовать cat для подсчета строк. Это антиобразец назвать бесполезным использование кот (UUoC). Для подсчета строк в файлах текущего каталога используйте wc:

wc -l * 

тут повторяется на страницах каталогов:

find . -name "*.c" -exec wc -l {} \;
  • . это имя верхнего каталога, чтобы начать поиск из

  • -name "*.c" - это образец файла вы заинтересованы в

  • -exec дает команду для выполнения

  • {} является результатом команды find, которая должна быть передана команде (здесь wc-l)

  • \; указывает на конец команды

эта команда создает список всех файлов, найденных с их количеством строк, Если вы хотите иметь сумму для все найденные файлы можно использовать найдите список файлов (с помощью -print option) и чем использовать xargs для передачи этого списка в качестве аргумента wc-l.

find . -name "*.c" -print | xargs wc -l 

EDIT to address Robert Gamble комментарий (спасибо): если у вас есть пробелы или новые строки (!) в именах файлов, то вы должны использовать вместо -print и xargs -null чтобы список имен файлов обменивался строками с нулевым завершением.

find . -name "*.c" -print0 | xargs -0 wc -l

философия Unix состоит в том, чтобы иметь инструменты, которые делают только одну вещь, и делают это что ж.


если вы хотите код-гольф ответ:

grep '' -R . | wc -l 

проблема только с использованием wc-l сама по себе, это не может хорошо спуститься, и oneliners с помощью

find . -exec wc -l {} \;

не даст вам общее количество строк, потому что он запускает wc один раз для каждого файла, ( loL! ) и

find . -exec wc -l {} + 

будет запутаться, как только найти хиты ~200k1,2 ограничение аргументов символов для параметров и вместо этого вызывает wc несколько раз, каждый раз, давая вам только частичное резюме.

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

за стоимость 1 дополнительного командного символа вы можете полностью игнорировать двоичные файлы:

 grep '' -IR . | wc -l

если вы хотите запустить line рассчитывает на двоичные файлы тоже

 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

это означает, что его собирается кусок очень очень легко.


Я думаю, что вы, вероятно, застряли с xargs

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

chromakodeметод дает тот же результат, но намного медленнее. Если вы используете xargs ваш кошкии wcing может начать, как только найти начинается поиск.

хорошее объяснение на Linux: xargs против exec {}


попробуйте использовать , который повторяется в каталоги по умолчанию:

find . -type f -execdir cat {} \; | wc -l


правильный путь:

find . -name "*.c" -print0 | xargs -0 cat | wc -l

вы должны использовать -print0, потому что в именах файлов Unix есть только два недопустимых символа: нулевой байт и "/" (Слэш). Так, например," xxx\npasswd " является допустимым именем. На самом деле, вы, скорее всего, столкнетесь с именами с пробелами в них. Команды выше будут считать каждое слово как отдельный файл.

вы также можете использовать "- type f " вместо-name, чтобы ограничить поиск файлами.


использование cat или grep в приведенных выше решениях расточительно, если вы можете использовать относительно недавние инструменты GNU, включая Bash:

wc -l --files0-from=<(find . -name \*.c -print0)

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


мне нравится использовать найти и глава вместе для "рекурсивного кота" на всех файлах в каталоге проекта, например:

find . -name "*rb" -print0 | xargs -0 head -10000

преимущество в том, что head добавит ваше имя файла и путь:

==> ./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, но для "неофициального просмотра проекта / каталога" этот подход работает очень хорошо для меня.


Если вы хотите создать только общее количество строк, а не количество строк для каждого файла что-то вроде:

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

работает хорошо. Это избавляет вас от необходимости выполнять дальнейшую фильтрацию текста в скрипте.


wc -cl `find . -name "*.php" -type f`

вот скрипт 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`
    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

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


find . -name "*.h" -print | xargs wc -l