Monitor progress of written lines of code Not long ago, I was asked about how many lines of code I have written in C++ and could not answer that question. For this reason and to become more familiar with Bash shell scripting, I wrote a small system to monitor the lines of code written in a specific subdirectory.

Currently, I count the lines of code at 5 seconds interval and write the difference (if favorable) to a file.

As mention above, I am not familiar with bash scripting and hope to get some helpful feedback.

I would appreciate the advice, especially in the following areas:


Code style (readability, naming conventions)
Efficiency (how to avoid unnecessary complexity)
How can I prevent a long list of extension as used currently in my
approach (-name "*.py" -o -name "*.cpp" -o -name "*.h"). Can I do
something like [py, cpp, h, ...] instead?




count_lines () {
    N="$(find ./ -name "*.py" -o -name "*.cpp" -o -name "*.h" | \
    xargs grep -cve "^\s*$" | grep -oP '(?&lt;=:).*' | \
    awk '{s+=$1} END {print s}')"
    echo "$N"
}

FILE_NAME="counter.log"
touch $FILE_NAME
SUM=0

while true; do 
    NUM1=$(count_lines) 
    sleep 5;
    NUM2=$(count_lines) 
    DIFF=$((NUM2-NUM1))
    if [ "$DIFF" -gt 0 ]; then
        SUM=$((SUM+DIFF))
    fi
    echo "${SUM} ${NUM2}" &gt;&gt; $FILE_NAME
done
This isn't any shorter, but it is more dynamic:

exts=( py cpp h )

count_lines() {
    local find_args=( -false )
    for ext in "${exts[@]}"; do
        find_args+=( -o -name "*.$ext" )
    done

    find ./ "${find_args[@]}" -print0 |
    xargs -o grep -cve "^\s*$" |
    grep -oP '(?&lt;=:).*' |
    awk '{s+=$1} END {print s}'
}


The extensions reside in a bash array that can live in the global scope. It's one place to store your list of interesting files.

In count_lines you can build up an array of arguments to pass on to find. I'm using -false as the first one so that it's simple to add -o -name "*.something in the loop.

You don't need to capture the command output only to print it on the next line. Just let the commands print to stdout directly.

I added -print0 to find and -0 to xargs. These options work well together to be able to handle any filename, regardless of any whitespace in the name.

Note you don't need to use line continuations when the line ends with a pipe (or with a &amp;&amp; or ||) -- bash understands that the pipeline continues on the next line.

About your awk command: if your goal is to count lines, don't you want {s+=1} or {s++} instead of {s+=$1}? The latter will only sum any filenames that look like numbers:

$ touch 5 8 a b c
$ ls | awk '{sum += $1; count++} END {print sum, count}'
13 5