Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to count lines of code including sub-directories [duplicate]

Tags:

linux

bash

unix

wc

Suppose I want to count the lines of code in a project. If all of the files are in the same directory I can execute:

cat * | wc -l 

However, if there are sub-directories, this doesn't work. For this to work cat would have to have a recursive mode. I suspect this might be a job for xargs, but I wonder if there is a more elegant solution?

like image 863
speciousfool Avatar asked Nov 25 '08 07:11

speciousfool


People also ask

How do you counts the number of directories and sub directories in the current directory?

An easy way of counting files and directories in a directory is to use the “tree” command and to specify the name of the directory to be inspected. As you can see, the number of files and directories is available at the bottom of the tree command. The “tree” command is not installed on all hosts by default.

How do you count source of lines of code?

To use cloc simply type cloc followed by the file or directory which you wish to examine. Now lets run cloc on it. As you can see it counted the number of files, blank lines, comments and lines of code. Another cool feature of cloc is that can even be used on compressed files.


2 Answers

First you do not need to use cat to count lines. This is an antipattern called Useless Use of Cat (UUoC). To count lines in files in the current directory, use wc:

wc -l *  

Then the find command recurses the sub-directories:

find . -name "*.c" -exec wc -l {} \; 
  • . is the name of the top directory to start searching from

  • -name "*.c" is the pattern of the file you're interested in

  • -exec gives a command to be executed

  • {} is the result of the find command to be passed to the command (here wc-l)

  • \; indicates the end of the command

This command produces a list of all files found with their line count, if you want to have the sum for all the files found, you can use find to list the files (with the -print option) and than use xargs to pass this list as argument to wc-l.

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

EDIT to address Robert Gamble comment (thanks): if you have spaces or newlines (!) in file names, then you have to use -print0 option instead of -print and xargs -null so that the list of file names are exchanged with null-terminated strings.

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

The Unix philosophy is to have tools that do one thing only, and do it well.

like image 181
philant Avatar answered Sep 24 '22 01:09

philant


If you want a code-golfing answer:

grep '' -R . | wc -l  

The problem with just using wc -l on its own is it cant descend well, and the oneliners using

find . -exec wc -l {} \; 

Won't give you a total line count because it runs wc once for every file, ( loL! ) and

find . -exec wc -l {} +  

Will get confused as soon as find hits the ~200k1,2 character argument limit for parameters and instead calls wc multiple times, each time only giving you a partial summary.

Additionally, the above grep trick will not add more than 1 line to the output when it encounters a binary file, which could be circumstantially beneficial.

For the cost of 1 extra command character, you can ignore binary files completely:

 grep '' -IR . | wc -l 

If you want to run line counts on binary files too

 grep '' -aR . | wc -l  
Footnote on limits:

The docs are a bit vague as to whether its a string size limit or a number of tokens limit.

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 

This implies its going to chunk very very easily.

like image 25
Kent Fredric Avatar answered Sep 22 '22 01:09

Kent Fredric