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

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


person Jonathan Hartley    schedule 22.09.2008    source источник
comment
Многие приведенные ниже решения работают только для одного файла (например, foo.c). Любые мысли о общем количестве строк в проекте (например, много файлов в структуре каталогов и исключая двоичные файлы)?   -  person solvingPuzzles    schedule 15.09.2012
comment
@solvingPuzzles Думаю, я могу ответить на эту часть. Для любого решения, которое работает с одним файлом, например. ФАЙЛ кота | sed blah, вы можете работать со многими файлами, заменив cat FILE командой, в которой перечислены имена файлов для работы, например. найти . -name '*.py' и передайте его в xargs cat. например найти . -имя '*.py' | кот xargs | sed '/^\s*$/d' | туалет -л   -  person Jonathan Hartley    schedule 18.09.2012
comment
@JonathanHartley @solvingPuzzles есть также такие программы, как sloc и cloc, которые здесь для подсчета строк кода.   -  person AsTeR    schedule 17.02.2015
comment
ОП здесь: когда я впервые задал эту проблему, «cloc» не очень хорошо справился с кодом Python. В наше время это здорово.   -  person Jonathan Hartley    schedule 25.10.2016
comment
cloc также доступен в виде модуля npm и экономит много времени.   -  person Krishna Vedula    schedule 06.11.2017


Ответы (19)


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

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

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

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

person Michael Cramer    schedule 22.09.2008
comment
Не уверен, почему вы используете кошку там. Используйте foo.c или foo.pl в качестве имени файла для передачи в sed. sed '/^\s*$/d' foo.c | туалет -л - person Andy Lester; 24.09.2008
comment
Просто привычка. Я читаю пайплайны слева направо, то есть обычно начинаю с кота, затем действие, действие, действие и т. д. Понятно, что конечный результат один и тот же. - person Michael Cramer; 24.09.2008
comment
Чтобы сделать это для всех файлов во всех подпапках и исключить комментарии с '//', расширьте эту команду следующим образом: find . -type f -name '*.c' -exec cat {} \; | sed '/^\s*#/d;/^\s*$/d;/^\s*\/\//d' | туалет -л - person Benjamin Intal; 08.07.2010
comment
@Andy: Дайте ему награду за бесполезное использование кошек! - person Andrew Grimm; 01.11.2010
comment
Вы можете читать слева направо без UUOC: < foo.pl sed 'stuff' | wc -l. - person jw013; 05.12.2011
comment
Вообще говоря, UUOC не важен, важна читабельность. - person andersand; 22.02.2012
comment
Если файлов несколько, find -exec работает медленно, так как запускает новый экземпляр cat для каждого файла. Это даже не встроенный в оболочку cat, а /bin/cat, так что у вас есть целая fork/exec для каждого файла. Используйте найти. -тип f | кот xargs | sed или, если в именах файлов есть пробелы, найдите . -тип f -print0 | xargs -0 кошка | сед. Говоря об этом, вам даже не нужен cat, так как sed занимает несколько файлов. Таким образом, найдите . -type f -name '.c' | xargs sed -r '/^\s*(\/\/.)?$/d' | wc -l' работает просто отлично (за исключением надоедливых /* */ многострочных комментариев) - person dannysauer; 30.08.2013
comment
Это сработало для меня grep -c '^$' $YOURFILE из здесь . - person divinedragon; 11.09.2014
comment
Пожалуйста, рассмотрите возможность добавления cat file | wc -l. Я заметил, что вопрос ищет непустые строки; тем не менее, для справки было бы неплохо, так как это первый результат Google для строк подсчета bash (по крайней мере, для меня это было). - person Qw3ry; 18.08.2017
comment
@divinedragon Это считает пустые строки; чтобы считать непустым, просто инвертируйте соответствие с -v: grep -vc '^$' $YOURFILE. Чтобы включить только пробельные строки как пустые, см. Ответ SpoonMeiser. - person Jacktose; 13.03.2019
comment
Вот код, если вы хотите найти строку для каждого из файлов .sh в текущем каталоге отдельно for f in *.sh; do lines=$(sed '/^\s*#/d;/^\s*$/d' $f | wc -l); echo ${f} : ${lines}; done - person Mirza Prangon; 31.03.2021

#!/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 являются расширениями просматриваемых файлов. Любые файлы с другим расширением игнорируются.

person Gilles    schedule 22.09.2008
comment
Вариант для приложения Rails: find . -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' | туалет -л - person poseid; 18.03.2012
comment
Вам нужно добавить $ к grep (...\.js$|...), иначе он будет соответствовать feature.js.swp. - person Xeoncross; 13.03.2015
comment
Вы забыли привязку, поэтому она включает неправильные файлы. И еще более простой вариант с привязкой: find . | egrep '.\.c$|.\.h$' | xargs cat | sed '/^\s*$/d' | wc -l - person Mark Jeronimus; 14.12.2017

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

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

person xsl    schedule 22.09.2008
comment
Когда я впервые задал этот вопрос, «cloc» посчитал строки документации Python строками кода, что было неоптимально, ИМХО. Современные версии cloc теперь считают строки документации Python комментариями, что мне нравится гораздо больше. - person Jonathan Hartley; 30.06.2016
comment
Это правильный ответ! Я только что попробовал cloc, и он хорошо справляется со своей задачей. - person LeeMobile; 08.07.2019

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

Мое решение:

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
person SpoonMeiser    schedule 22.09.2008
comment
Спасибо! Между прочим, wc действительно предоставляет количество для каждого данного файла плюс общее количество. - person Jonathan Hartley; 10.11.2009
comment
Однако нет, если вы подключаетесь к нему, поскольку стандарт считается одним файлом. - person SpoonMeiser; 10.11.2009
comment
Это лучший ответ на мой взгляд. - person simhumileco; 10.04.2018
comment
-e не нужно. Это нормальное позиционное расположение паттерна, и вы не делаете с ним ничего странного. Но нет ничего плохого в том, чтобы быть откровенным, если это ваш стиль. - person Jacktose; 13.03.2019

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

person coastline    schedule 04.06.2014
comment
Этот ответ самый простой - person samthebest; 13.03.2018
comment
В этой цепочке нет необходимости в cat: grep -v ^$ fileName | wl -l - person Aethalides; 09.08.2018
comment
Также нет необходимости в wc -l, потому что у grep есть -c: grep -vc ^$ fileName - person Jacktose; 13.03.2019

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

wc *.py

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

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

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

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

person Community    schedule 22.09.2008
comment
\W не соответствует пробелу, он соответствует несловесным символам. Это противоположность \w, словесных символов. \W Соответствует всему, что не является буквенно-цифровым или символом подчеркивания, и, следовательно, не будет выполнять то, что здесь заявлено. Ты имеешь в виду - person SpoonMeiser; 01.10.2008

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

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

person curtisk    schedule 22.09.2008
comment
Зачем использовать cat и передавать файл в grep, если вы можете передать имя файла в качестве аргумента в grep? - person SpoonMeiser; 22.09.2008
comment
правда, это просто старый псевдоним, который у меня есть... он делает то же самое, что и ваше решение, вместо использования обратного - person curtisk; 22.09.2008

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, где строки комментариев начинаются с / или * (я использую * в каждой строке многострочного комментария).

person sami    schedule 14.02.2014
comment
Это рабочее решение. Единственное, на что следует обратить внимание: многострочные комментарии не учитываются. - person Amol; 11.09.2018

Вот сценарий 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

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

person curran    schedule 01.04.2014

Самая аккуратная команда

grep -vc ^$ fileName

с опцией -c вам даже не нужно wc -l

person Son Nguyen    schedule 01.10.2020

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

grep -c '.' <list of files>

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

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

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

person Linor    schedule 22.09.2008
comment
. соответствует пробелу. Это решение работает только в том случае, если вы считаете строку, содержащую только пробелы, непустой, что технически так и есть, хотя, вероятно, это не то, что вам нужно. - person SpoonMeiser; 22.09.2008

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

#!/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
person Keith Pinson    schedule 14.08.2011
comment
Спасибо @Andy Lester (+1 к вашему комментарию) за непустую часть рецепта. - person Keith Pinson; 14.08.2011
comment
Также спасибо @Michael Cramer (+1 к вашему сообщению) за первоначальную публикацию (чуть более подробного) непустого решения. - person Keith Pinson; 14.08.2011

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

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

Это не более чем набор предыдущих решений.

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

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

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

ХТХ!

person Dutch    schedule 03.01.2011
comment
\W — символы, не являющиеся словами; например, это не будет соответствовать такой строке, как ${-[*]} + $@. Что, безусловно, является действительным кодом где-то в мире. ;) Вы имеете в виду \s для пробела. - person dannysauer; 30.08.2013

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

grep -v ^$ filename wc -l | sed -e 's/ //g' 
person mahesh    schedule 23.02.2011

rgrep . | wc -l

дает количество непустых строк в текущем рабочем каталоге.

person jean-emmanuel    schedule 08.12.2016

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

Просто

wc -l *.c 

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

person G1i1ch    schedule 05.05.2012
comment
Привет. 'wc' сам по себе не ищет подкаталоги и не отфильтровывает пустые строки, которые явно запрашиваются в вопросе. - person Jonathan Hartley; 08.05.2012
comment
wc считает пустые строки. ОП хочет подсчитать непустые строки. Это правда, что он захочет использовать wc, но только после того, как он будет отредактирован с помощью sed. - person EhevuTov; 21.09.2012

person    schedule
comment
люблю простоту этого ???????? - person Gerard; 16.04.2020

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