4
\$\begingroup\$

I'm a HPC guy so I'm all about "make it work, then make it fast." I have a little bash script which gets a Physical Source Lines Of Code (PSLOC) and Logical SLOC (currently just of Java code, but it would work for C and C++ too). It works by finding all *.java files in a directory and then goes through each file found and uses sed to delete stuff I don't want. It first does PSLOC by deleting all comments, whitespace, and blank lines. It then gets LSLOC by taking PSLOC and deleting all lines starting with # or @, replacing {}()'s with a blank space, deleting whitespace, and finally deleting blank lines. I get the line count for PSLOC and LSLOC with wc -l.

This works, but I'm a scripting noob and haven't done anything like this before. What I'm wondering is how can I make this script faster and easier to read/maintain:

#!/bin/bash
DIR="C:/dev/somejavafolder"
LANGUAGE="java"
find "$DIR" -type f -name "*.$LANGUAGE" > filelist
while read FILE; do

   PSLOC="$FILE.psloc"
   LSLOC="$FILE.lsloc"

   # Get PSLOC
   sed -e "s/\/\/.*$//" $FILE > $PSLOC # deletes all /* to */ lines
   sed -i -e 's|/\*|\n&|g;s|*/|&\n|g' $PSLOC # ^
   sed -i -e '/\/\*/,/*\//d' $PSLOC # deletes all // lines
   sed -i -e 's/^[ \t]*//' -e 's/[ \t]*$//' $PSLOC # deletes all whitespace
   sed -i -e '/^$/d' $PSLOC # deletes all blank lines

   wc -l $PSLOC

   # Get LSLOC
   sed -e 's/#.*//' $PSLOC > $LSLOC # deletes all # lines
   sed -i -e 's/@.*//' $LSLOC # deletes all # lines
   sed -i -e 's/{/ /g;s/}/ /g;s/)/ /g;s/(/ /g' $LSLOC # replaces {}() with spaces
   sed -i -e 's/^[ \t]*//' -e 's/[ \t]*$//' $LSLOC # deletes all whitespace
   sed -i -e '/^$/d' $LSLOC # deletes all blank lines

   wc -l $LSLOC

done < filelist

find "$DIR" -name "*.*sloc" -type f -delete

This gets PSLOC and LSLOC counts of 531 java files (~80524 lines) in about 4 minutes.

Edit: per @choroba's suggestion, I changed the file to

#!/bin/bash
DIR="C:/dev/somejavafolder"
LANGUAGE="java"
find "$DIR" -type f -name "*.$LANGUAGE" > filelist
while read FILE; do  

   PSLOC="$FILE.psloc"
   LSLOC="$FILE.lsloc"
   sed -e "s/\/\/.*$//" -e 's|/\*|\n&|g;s|*/|&\n|g' -e '/\/\*/,/*\//d' -e 's/^[ \t]*//' -e 's/[ \t]*$//' -e '/^$/d' $FILE > $PSLOC # deletes all /* to */ lines
   wc -l $PSLOC
   sed -e 's/#.*//' -e 's/@.*//' -e 's/{/ /g;s/}/ /g;s/)/ /g;s/(/ /g' -e 's/^[ \t]*//' -e 's/[ \t]*$//' -e '/^$/d' $PSLOC > $LSLOC # deletes all # lines
   wc -l $LSLOC

done < filelist 

find "$DIR" -name "*.*sloc" -type f -delete

and the runtime went down to about 80 seconds. Awesome! Any other ideas?

Edit 2: So now it's even more succinct without writing the changes to files, just spitting out the linecount. How would I go about spitting the two numbers resulting from sed ... | wc -l on the same line separated by a space without doing some assignment like a=($(sed ... | wc -l)) and using echo?

#!/bin/bash
DIR="C:/dev/somejavafolder"
LANGUAGE="java"

wc -l `find $DIR -type f -name '*.java'` > OSLOC
sed -i -e "s/^[ \t]*//" -e "s/[ \t]*$//" OSLOC

find "$DIR" -type f -name "*.$LANGUAGE" > filelist
while read FILE; do

   # Get PSLOC 
   sed -e "s/\/\/.*$//" -e "s|/\*|\n&|g;s|*/|&\n|g" -e "/\/\*/,/*\//d" -e "s/^[ \t]*//" -e "s/[ \t]*$//" -e "/^$/d" $FILE | wc -l

   # Get LSLOC
   sed -e "s/\/\/.*$//" -e "s|/\*|\n&|g;s|*/|&\n|g" -e "/\/\*/,/*\//d" -e "s/#.*//" -e "s/@.*//" -e "s/{/ /g;s/}/ /g;s/)/ /g;s/(/ /g" -e "s/^[ \t]*//" -e "s/[ \t]*$//" -e "/^$/d" $FILE | wc -l

done < filelist

find "$DIR" -name "*.*sloc" -type f -delete
\$\endgroup\$
  • 1
    \$\begingroup\$ Can't you stack all the sed expressions into several -e's of one sed call? \$\endgroup\$ – choroba Nov 6 '15 at 15:46
  • \$\begingroup\$ @choroba, would it be possible to combine the wc -l with the single line sed calls so that it just counts what the file would be without actually writing it? \$\endgroup\$ – mjswartz Nov 6 '15 at 16:37
  • 1
    \$\begingroup\$ Sure, instead of > file do | wc -l. \$\endgroup\$ – choroba Nov 6 '15 at 17:18
  • \$\begingroup\$ @choroba, see my second edit for another question about formatting the output \$\endgroup\$ – mjswartz Nov 6 '15 at 17:46
  • \$\begingroup\$ BTW Java code comments don't start with # or @. \$\endgroup\$ – h.j.k. Nov 11 '15 at 2:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.