How can I count all the lines of code in a directory recursively?

BashShell

Bash Problem Overview


We've got a PHP application and want to count all the lines of code under a specific directory and its subdirectories.

We don't need to ignore comments, as we're just trying to get a rough idea.

wc -l *.php 

That command works great for a given directory, but it ignores subdirectories. I was thinking the following comment might work, but it is returning 74, which is definitely not the case...

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

What's the correct syntax to feed in all the files from a directory resursively?

Bash Solutions


Solution 1 - Bash

Try:

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

or (when file names include special characters such as spaces)

find . -name '*.php' | sed 's/.*/"&"/' | xargs  wc -l

The SLOCCount tool may help as well.

It will give an accurate source lines of code count for whatever hierarchy you point it at, as well as some additional stats.

Sorted output:

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

Solution 2 - Bash

For another one-liner:

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

It works on names with spaces and only outputs one number.

Solution 3 - Bash

You can use the cloc utility which is built for this exact purpose. It reports each the amount of lines in each language, together with how many of them are comments, etc. CLOC is available on Linux, Mac and Windows.

Usage and output example:

$ 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
-------------------------------------------------------------------------------

Solution 4 - Bash

If using a decently recent version of Bash (or ZSH), it's much simpler:

wc -l **/*.php

In the Bash shell this requires the globstar option to be set, otherwise the ** glob-operator is not recursive. To enable this setting, issue

shopt -s globstar

To make this permanent, add it to one of the initialization files (~/.bashrc, ~/.bash_profile etc.).

Solution 5 - Bash

On Unix-like systems, there is a tool called cloc which provides code statistics.

I ran in on a random directory in our code base it says:

      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
-------------------------------------------------------------------------------

Solution 6 - Bash

You didn't specify how many files are there or what is the desired output.

This may be what you are looking for:

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

Solution 7 - Bash

Yet another variation :)

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

This will give the total sum, instead of file-by-file.

Add . after find to make it work.

Solution 8 - Bash

Use find's -exec and awk. Here we go:

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

This snippet finds for all files (-type f). To find by file extension, use -name:

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

Solution 9 - Bash

More common and simple as for me, suppose you need to count files of different name extensions (say, also natives):

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

Solution 10 - Bash

There is a little tool called sloccount to count the lines of code in a directory.

It should be noted that it does more than you want as it ignores empty lines/comments, groups the results per programming language and calculates some statistics.

Solution 11 - Bash

POSIX

Unlike most other answers here, these work on any POSIX system, for any number of files, and with any file names (except where noted).


Lines in each file:

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 {} +

Lines in each file, sorted by file path

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

Lines in each file, sorted by number of lines, descending

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

Total lines in all files

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

Solution 12 - Bash

The tool Tokei displays statistics about code in a directory. Tokei will show the number of files, total lines within those files and code, comments, and blanks grouped by language. Tokei is also available on Mac, Linux, and Windows.

An example of the output of Tokei is as follows:

$ 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 can be installed by following the instructions on the README file in the repository.

Solution 13 - Bash

You want a simple for loop:

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

Solution 14 - Bash

For sources only:

wc `find`

To filter, just use grep:

wc `find | grep .php$`

Solution 15 - Bash

A straightforward one that will be fast, will use all the search/filtering power of find, not fail when there are too many files (number arguments overflow), work fine with files with funny symbols in their name, without using xargs, and will not launch a uselessly high number of external commands (thanks to + for find's -exec). Here you go:

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

Solution 16 - Bash

I know the question is tagged as [tag:bash], but it seems that the problem you're trying to solve is also PHP related.

Sebastian Bergmann wrote a tool called PHPLOC that does what you want and on top of that provides you with an overview of a project's complexity. This is an example of its report:

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

As you can see, the information provided is a lot more useful from the perspective of a developer, because it can roughly tell you how complex a project is before you start working with it.

Solution 17 - Bash

None of the answers so far gets at the problem of filenames with spaces.

Additionally, all that use xargs are subject to fail if the total length of paths in the tree exceeds the shell environment size limit (defaults to a few megabytes in Linux).

Here is one that fixes these problems in a pretty direct manner. The subshell takes care of files with spaces. The awk totals the stream of individual file wc outputs, so it ought never to run out of space. It also restricts the exec to files only (skipping directories):

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

Solution 18 - Bash

If you want to keep it simple, cut out the middleman and just call wc with all the filenames:

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

Or in the modern syntax:

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

This works as long as there are no spaces in any of the directory names or filenames. And as long as you don't have tens of thousands of files (modern shells support really long command lines). Your project has 74 files, so you've got plenty of room to grow.

Solution 19 - Bash

> WC -L ? better use GREP -C ^

wc -l? Wrong!

The wc command counts new lines codes, not lines! When the last line in the file does not end with new line code, this will not be counted!

If you still want count lines, use grep -c ^. Full example:

# 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 of '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

Finally, watch out for the wc -l trap (counts enters, not lines!!!)

Solution 20 - Bash

Giving out the longest files first (ie. maybe these long files need some refactoring love?), and excluding some vendor directories:

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

Solution 21 - Bash

For Windows, an easy-and-quick tool is LocMetrics.

Solution 22 - Bash

You can use a utility called codel (link). It's a simple Python module to count lines with colorful formatting.

Installation
pip install codel
Usage

To count lines of C++ files (with .cpp and .h extensions), use:

codel count -e .cpp .h

You can also ignore some files/folder with the .gitignore format:

codel count -e .py -i tests/**

It will ignore all the files in the tests/ folder.

The output looks like:

Long output

You also can shorten the output with the -s flag. It will hide the information of each file and show only information about each extension. The example is below:

Short output

Solution 23 - Bash

Very simply:

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

Solution 24 - Bash

If you want your results sorted by number of lines, you can just add | sort or | sort -r (-r for descending order) to the first answer, like so:

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

Solution 25 - Bash

Something different:

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

This works out fine, but you need to have at least one *.php file in the current folder or one of its subfolders, or else wc stalls.

Solution 26 - Bash

It’s very easy with Z shell (zsh) globs:

wc -l ./**/*.php

If you are using Bash, you just need to upgrade. There is absolutely no reason to use Bash.

Solution 27 - Bash

If you need just the total number of lines in, let's say, your PHP files, you can use very simple one line command even under Windows if you have GnuWin32 installed. Like this:

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

You need to specify where exactly is the find.exe otherwise the Windows provided FIND.EXE (from the old DOS-like commands) will be executed, since it is probably before the GnuWin32 in the environment PATH and has different parameters and results.

Please note that in the command above you should use back-quotes, not single quotes.

Solution 28 - Bash

On OS X at least, the find+xarg+wc commands listed in some of the other answers prints "total" several times on large listings, and there is no complete total given. I was able to get a single total for .c files using the following command:

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

Solution 29 - Bash

While I like the scripts, I prefer this one as it also shows a per-file summary as long as a total:

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

Solution 30 - Bash

You don't need all these complicated and hard to remember commands. You just need a Python tool called line-counter.

A quick overview

This is how you get the tool

$ pip install line-counter

Use the line command to get the file count and line count under current directory (recursively):

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

If you want more detail, just use 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

And the best part of this tool is, you can add a .gitignore-like configuration file to it. You can set up rules to select or ignore what kind of files to count just like what you do in '.gitignore'.

More description and usage is here: https://github.com/MorganZhang100/line-counter

Solution 31 - Bash

If you're on Linux (and I take it you are), I recommend my tool polyglot. It is dramatically faster than either sloccount or cloc and it is more featureful than sloccount.

You can invoke it with

poly .

or

poly

so it's much more user-friendly than some convoluted Bash script.

Solution 32 - Bash

If the files are too many, better to just look for the total line count.

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

Solution 33 - Bash

Similar to Shizzmo's answer, but uglier and more accurate. If you're using it often, modify it to suit and put it in a script.

This example:

  1. Properly excludes paths that aren't your code (not traversed at all by find)
  2. Filters out compound extensions and other files you wish to ignore
  3. Only includes actual files of the types you specify
  4. Ignores blank lines
  5. Gives a single number as a total
find . \! \( \( -path ./lib -o -path ./node_modules -o -path ./vendor -o -path ./any/other/path/to/skip -o -wholename ./not/this/specific/file.php -o -name '*.min.js' -o -name '*.min.css' \) -prune \) -type f \( -name '*.php' -o -name '*.inc' -o -name '*.js' -o -name '*.scss' -o -name '*.css' \) -print0 | xargs -0 cat | grep -vcE '^[[:space:]]*$'

Solution 34 - Bash

$cd directory
$wc -l* | sort -nr

Solution 35 - Bash

I used this inline-script that I launch from on a source project's directory:

 for i in $(find . -type f); do rowline=$(wc -l $i | cut -f1 -d" "); file=$(wc -l $i | cut -f2 -d" "); lines=$((lines + rowline)); echo "Lines["$lines"] " $file "has "$rowline"rows."; done && unset lines

That produces this output:

Lines[75]  ./Db.h has 75rows.
Lines[143]  ./Db.cpp has 68rows.
Lines[170]  ./main.cpp has 27rows.
Lines[294]  ./Sqlite.cpp has 124rows.
Lines[349]  ./Sqlite.h has 55rows.
Lines[445]  ./Table.cpp has 96rows.
Lines[480]  ./DbError.cpp has 35rows.
Lines[521]  ./DbError.h has 41rows.
Lines[627]  ./QueryResult.cpp has 106rows.
Lines[717]  ./QueryResult.h has 90rows.
Lines[828]  ./Table.h has 111rows.

Solution 36 - Bash

Excluding blank lines:

find . -name "*.php" | xargs grep -v -c '^$' | awk 'BEGIN {FS=":"} { $cnt = $cnt + $2} END {print $cnt}'

Including blank lines:

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

Solution 37 - Bash

I wanted to check on multiple file types and was to lazy to calculate the total by hand. So I use this now to get the total in one go.

find . -name '*.js' -or -name '*.php' | xargs wc -l | grep 'total'  | awk '{ SUM += $1; print $1} END { print "Total text lines in PHP and JS",SUM }'

> 79351
> 15318
> Total text lines in PHP and JS 94669

This allows you to chain multiple extension types you wish to filter on. Just add them in the -name '*.js' -or -name '*.php' part, and possibly modify the otuput message to your liking.

Solution 38 - Bash

First change the directory to which you want to know the number of lines.

For example, if I want to know the number of lines in all files of a directory named sample, give $cd sample.

Then try the command $wc -l *. This will return the number of lines for each file and also the total number of lines in the entire directory at the end.

Solution 39 - Bash

I do it like this:

Here is the lineCount.c file implementation:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int getLinesFromFile(const char*);

int main(int argc, char* argv[]) {
   int total_lines = 0;
   for(int i = 1; i < argc; ++i) {
       total_lines += getLinesFromFile(argv[i]); // *argv is a char*
   }

   printf("You have a total of %d lines in all your file(s)\n",    total_lines);
   return 0;
}


int getLinesFromFile(const char* file_name) {
    int lines = 0;
    FILE* file;
    file = fopen(file_name, "r");
    char c = ' ';
    while((c = getc(file)) != EOF)
        if(c == '\n')
            ++lines;
    fclose(file);
    return lines;
}

Now open the command line and type gcc lineCount.c. Then type ./a.out *.txt.

This will display the total lines of files ending with .txt in your directory.

Solution 40 - Bash

If you want to count LOC you have written, you may need to exclude some files.

For a Django project, you may want to ignore the migrations and static folders. For a JavaScript project, you may exclude all pictures or all fonts.

find . \( -path '*/migrations' -o -path '*/.git' -o -path '*/.vscode' -o -path '*/fonts' -o -path '*.png' -o -path '*.jpg' -o -path '*/.github' -o -path '*/static' \) -prune -o -type f -exec cat {} + | wc -l

Usage here is as follows:

*/folder_name
*/.file_extension

To list the files, modify the latter part of the command:

find . \( -path '*/migrations' -o -path '*/.git' -o -path '*/.vscode' -o -path '*/fonts' -o -path '*.png' -o -path '*.jpg' -o -path '*/.github' -o -path '*/static' \) -prune -o --print

Solution 41 - Bash

On Windows PowerShell try this:

dir -Recurse *.php | Get-Content | Measure-Object -Line

Solution 42 - Bash

I have BusyBox installed on my Windows system. So here is what I did.

ECHO OFF
for /r %%G in (*.php) do (
busybox grep . "%%G" | busybox wc -l
)

Solution 43 - Bash

Yet another command to get the sum of all files (Linux of course)

find ./ -type f -exec wc -l {}  \; | cut -d' ' -f1 | paste -sd+ | bc

Main difference from other answers:

  1. using find -exec,
  2. using paste (with cut),
  3. using bc

Solution 44 - Bash

Here's a flexible one using older Python (works in at least Python 2.6) incorporating Shizzmo's lovely one-liner. Just fill in the types list with the filetypes you want counted in the source folder, and let it fly:

#!/usr/bin/python

import subprocess

rcmd = "( find ./ -name '*.%s' -print0 | xargs -0 cat ) | wc -l"
types = ['c','cpp','h','txt']

sum = 0
for el in types:
    cmd = rcmd % (el)
    p = subprocess.Popen([cmd],stdout=subprocess.PIPE,shell=True)
    out = p.stdout.read().strip()
    print "*.%s: %s" % (el,out)
    sum += int(out)
print "sum: %d" % (sum)

Solution 45 - Bash

I may as well add another OS X entry, this one using plain old find with exec (which I prefer over using xargs, as I have seen odd results from very large find result sets with xargs in the past).

Because this is for OS X, I also added in the filtering to either .h or .m files - make sure to copy all the way to the end!

find ./ -type f -name "*.[mh]" -exec wc -l {}  \; | sed -e 's/[ ]*//g' | cut -d"." -f1 | paste -sd+ - | bc

Solution 46 - Bash

lines=0 ; for file in *.cpp *.h ; do lines=$(( $lines + $( wc -l $file | cut -d ' ' -f 1 ) )) ; done ; echo $lines

Solution 47 - Bash

if u use window so easly 2 steps:

  1. install cloc for example open cmd for admin and write next code => choco install cloc
  2. then use cd or open terminal in folder with projects and write next code => clocl project-example

sreens with steps:

  1. enter image description here
  2. enter image description here

p.s. need move or remove folder with build project and node_modules

Solution 48 - Bash

cat \`find . -name "*.php"\` | wc -l

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser77413View Question on Stackoverflow
Solution 1 - BashPeter ElespuruView Answer on Stackoverflow
Solution 2 - BashShizzmoView Answer on Stackoverflow
Solution 3 - BashsimaoView Answer on Stackoverflow
Solution 4 - BashMichael WildView Answer on Stackoverflow
Solution 5 - BashCalmariusView Answer on Stackoverflow
Solution 6 - BashPaweł PolewiczView Answer on Stackoverflow
Solution 7 - BashMotiejus JakštysView Answer on Stackoverflow
Solution 8 - BashjonhattanView Answer on Stackoverflow
Solution 9 - BashsergeychView Answer on Stackoverflow
Solution 10 - BashsebasgoView Answer on Stackoverflow
Solution 11 - BashPaul DraperView Answer on Stackoverflow
Solution 12 - BashJoel EllisView Answer on Stackoverflow
Solution 13 - BashennuikillerView Answer on Stackoverflow
Solution 14 - BashkekszumquadratView Answer on Stackoverflow
Solution 15 - Bashgniourf_gniourfView Answer on Stackoverflow
Solution 16 - BashJa͢ckView Answer on Stackoverflow
Solution 17 - BashGeneView Answer on Stackoverflow
Solution 18 - BashalexisView Answer on Stackoverflow
Solution 19 - BashZnikView Answer on Stackoverflow
Solution 20 - BashMattView Answer on Stackoverflow
Solution 21 - BashwalvView Answer on Stackoverflow
Solution 22 - BashvoilalexView Answer on Stackoverflow
Solution 23 - Bashghostdog74View Answer on Stackoverflow
Solution 24 - BashPaul PettengillView Answer on Stackoverflow
Solution 25 - BashnavView Answer on Stackoverflow
Solution 26 - BashHappyFaceView Answer on Stackoverflow
Solution 27 - BashNeven BoyanovView Answer on Stackoverflow
Solution 28 - BashDoug RichardsonView Answer on Stackoverflow
Solution 29 - BashakivaView Answer on Stackoverflow
Solution 30 - BashMorgan ZhangView Answer on Stackoverflow
Solution 31 - Bashuser8174234View Answer on Stackoverflow
Solution 32 - BashbharathView Answer on Stackoverflow
Solution 33 - BashWalfView Answer on Stackoverflow
Solution 34 - BashussView Answer on Stackoverflow
Solution 35 - BashLuca DavanzoView Answer on Stackoverflow
Solution 36 - BashVladimir VenediktovView Answer on Stackoverflow
Solution 37 - BashTschallackaView Answer on Stackoverflow
Solution 38 - Bashvenky513View Answer on Stackoverflow
Solution 39 - BashMoshe RabaevView Answer on Stackoverflow
Solution 40 - BashVinayak BagariaView Answer on Stackoverflow
Solution 41 - BashYunus EşView Answer on Stackoverflow
Solution 42 - BashshyamView Answer on Stackoverflow
Solution 43 - BashAJedView Answer on Stackoverflow
Solution 44 - BashfyngyrzView Answer on Stackoverflow
Solution 45 - BashKendall Helmstetter GelnerView Answer on Stackoverflow
Solution 46 - BashAlexView Answer on Stackoverflow
Solution 47 - BashPaul AlexeevView Answer on Stackoverflow
Solution 48 - BashBjarni HerjolfssonView Answer on Stackoverflow