A one-line program to count lines of code

I wanted to sum the total lines of code in files in a given folder. I thought that writing my own program to do this would be faster than looking for it on the internet, so here's what I came up with (1 line broken into 7 lines to fit into your blog reader):

using System;
using System.Linq;
using System.IO;

class Program
    static void Main(string[] args)
                Environment.CurrentDirectory, "*", 
                string.Join(" ", args).Contains("/s") 
                    ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly)
            .Select(f => File.ReadAllLines(f).Length)

Just name the executable loc.exe and put it into your PATH - you're good to go. Input "loc" in the command prompt to get the total number of LOC in the current directory, and "loc /s" to do recursive search.

Please note that the way I wrote this program is not very good for debugging, because you can't put a breakpoint on substatements (technically speaking, this program consists of only one statement). In production code, I would rather write something like this:

string path = Environment.CurrentDirectory;
string pattern = "*";
string commandLine = string.Join(" ", args);
SearchOption searchRecursively = commandLine.Contains("/s") 
            ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
string[] files = Directory.GetFiles(path, pattern, searchRecursively); IEnumerable<int> lengths = files.Select(f => File.ReadAllLines(f).Length); int totalLOC = lengths.Sum();

because it better conveys the step-by-step actions and allows to put a breakpoint on any step. However, for my little program, my sense of style guided me to use the former notation.

As another side note, the "production version" doesn't use var for type inference. I think it improves readability in this case.

Comments (10)
  1. Christian Weyer says:

    One should use *.cs for C#-only files.

  2. Yes, I thought about passing the pattern as a command line parameter – we can leave it as an exercise to the reader 😉

  3. Just to clarify, I’m not proud or showing off or anything. This is just a posting so that this little trivial program is there when I need it – storing it in the cloud is better than somewhere deep in my harddrive.

    Luke Hoban wrote a ray-tracer as a single statement – now THAT’s something worth showing off.

  4. Jon Skeet says:

    That’s nasty – it reads all of each file into memory as it goes. Using LineReader – see http://csharpindepth.com/ViewNote.aspx?NoteID=113) you can make it neater:

    var query = files.Select(file => new LineReader(file).Count())


    LineReader is useful for any number of things, actually…

  5. Jon, I agree 🙂 Your LineReader does it the right way (stream).

    In my defense, I needed the program to count 20 kilobytes worth of files, so it took me about one minute to write this program without external dependencies. And, remembering that "Optimization is the root of all evil in programming", I didn’t bother. 🙂

    It’s a pity, actually, that IEnumerable<T> is not a native citizen in the framework from the very beginning. The Haskell’s (and Comega’s) list paradigm would make a lot of stuff better, e.g. your LineReader would be used instead of the current APIs etc. A lot of APIs use arrays where they could use IEnumerables (e.g. Reflection, or File IO, or string operations like Join or Split). In your book, you wrote about Streams not implementing IEnumerable yourself 🙂

    I might blog more about this someday.

  6. Caligula says:

    How about:

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

    Good grief.

  7. MercMan says:

    That was awesome!

    > How about:

    > $ find . -name "*" | xargs wc -l

    > Good grief.

  8. Apocalypse says:

    Hm, I usually use "sloccount" which is much more precise 🙂

  9. Caligula says:

    It was pointed out to me on dzone that my one-liner doesn’t take into account the recursive argument.

    So for non-recursive use find’s -maxdepth argument.

    And yeah–I had *totally* forgotten about sloccount, which is more meaningful in many cases!

  10. I would like to thank everyone for their input. Also I’d like to remind that this blog is about C# and .NET programming and various programming techniques.

    This post tries to demonstrate and contrast two programming styles in C#, and uses the line counting just as an example.

    If I really wanted to approach the problem seriously, I would just take NDepend to count the lines of code. If I ever wanted to count the lines of code in non-program files, I’d take PowerShell and learn how to do it there.

    This little program was just a fun coding exercise for me and I apologize for not making it clear at the beginning.



Comments are closed.

Skip to main content