Recursively count lines of code, excluding empty lines and comments Requirement: Write a program (in any language) that counts the number of lines of code in files matching *.sh in the directory tree starting from the directory that the program is executed in, excluding lines that are empty, only contain whitespace, or are just single-line comments (a line which the first character that is not a whitespace character is #). Files will only contain printable ASCII characters.

Output: A single integer representing the total count (can be followed by a newline too).

Here is an expanded solution in Python:

import os, sys

def recurse(dir = './'):
    count = 0

    for file in os.listdir(dir):
        if not os.path.isfile(dir + file):
            count += recurse(dir + file + '/')
        elif file.endswith('.sh'):
            with open(dir + file, 'r') as f:
                for line in f.read().split('\n'):
                    if (not line.strip().startswith('#')) and (not line.strip() == ''):
                        count += 1

    return count

sys.stdout.write(recurse())
PowerShell, 47 46 bytes



ls *.sh -r|gc|%{$o+=!($_-match'^\s*(#|$)')};$o


Try it online! (will always return 0 since there aren't any files)

Try it online! (here's a link that populates a dummy file so you can see the process)

-1 byte thanks to Neil

ls is alias for Get-ChildItem, specifying *.sh with the -recurse parameter, then we get-content of files. For each of those lines |%{...}, we accumulate into our $output a one if the Boolean !(...) statement is truthy. Inside the statement is a simple regex -match against the whitespace-only/comment/blank lines. Finally we leave $o on the pipeline.

The implicit Write-Output that happens at program completion adds a trailing newline, but that shouldn't matter in this case because the variable $o itself doesn't have a trailing newline nor does the actual return variable. It's a quirk of the shell, not a quirk of the program. For example, saving this to a script and executing that script in a pipeline will not have a newline.