0

Specify a command / set of commands that displays the number of lines of code in the .c and .h files in the current directory, displaying each file in alphabetical order followed by: and the number of lines in the files, and finally the total of the lines of code. . An example that might be displayed would be:

main.c: 202
util.c: 124
util.h: 43
TOTAL: 369

After many attempts, my final result of a one-liner command was :

wc -l *.c *.h | awk '{print $2 ": " $1}' | sed "$ s/total/TOTAL/g"

The problem is that i don't know how to sort them alphabetically without moving the TOTAL aswell (considering we don't know how many files are in that folder). I'm not sure if the command above is that efficient so if you have a better one you can include more variations of it.

JonBjatBun
  • 39
  • 5
  • `to sort them` - Would be great if you would post expected output matching the input showed. You want to sort it using file names? – KamilCuk Mar 16 '20 at 00:00

3 Answers3

1

You could save input into a variable, extract the last line, sort everything except the last line and then output the last line:

printf '%s\n' 'main.c: 202' 'util.c: 124' 'util.h: 43' 'TOTAL: 369' | {
    v=$(cat);
    total=$(tail -n1 <<<"$v");
    head -n-1 <<<"$v" | sort -r;
    printf "%s\n" "$total";
}
KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • Need to do it shorter and in a one-liner. Also the printf won't work as i mentioned --considering we don't know how many files are in the folder. – JonBjatBun Mar 16 '20 at 00:10
1

perhaps easier would be to sort the input arguments to wc -- perhaps something like this:

$ find . -maxdepth 1 '(' -name '*.py' -o -name '*.md' ')' | sort | xargs -d'\n' wc -l | awk '{print $2": "$1}' | sed 's/^total:/TOTAL:/'
./__main__.py: 70
./README.md: 96
./SCREENS.md: 76
./setup.py: 2
./t.py: 10
TOTAL: 254

note that I use xargs -d'\n' to avoid filenames with spaces in them (if I were targetting GNU+ I would drop the . from find . and perhaps use -print0 | sort -z | xargs -0 instead)

anthony sottile
  • 61,815
  • 15
  • 148
  • 207
  • Only one problem left with this command : how to remove the `./` from file names ? Also could you explain me how the `s/^total:/TOTAL:/` works without modifying file names ? – JonBjatBun Mar 16 '20 at 00:23
  • you could use more sed to do that: `sed 's|^\./||g'` for instance will remove the leading `./` -- as for "works without modifying filenames" -- it works unless the filename starts with `total:` – anthony sottile Mar 16 '20 at 00:25
  • Managed to solve that one. Also another problem : it shows hidden files. How can I fix that ? – JonBjatBun Mar 16 '20 at 08:50
  • can of course use more sed or grep or whatever to filter files that start with a `.` – anthony sottile Mar 16 '20 at 16:36
0

here's a meme-ier answer which uses python3.8+ (hey awk is turing complete why not use python?)

python3.8 -c 'import sys;s=0;[print(x+":",-s+(s:=s+len(list(open(x)))))for x in sorted(sys.argv[1:])];print("TOTAL:",s)' *.py *.cfg
__main__.py: 70
setup.cfg: 55
setup.py: 2
t.py: 10
TOTAL: 137

expanding it out, it abuses a few things:

  • len(list(open(x))) - open(x) returns a file, list exhausts the iterator (by lines) and then the length of that is the number of lines
  • -s+(s:=s+...) -- this is an assignment expression which has the side-effect of accumulating s but having the expression be the difference (...)
  • sorted(sys.argv) satisfies the sorting part
anthony sottile
  • 61,815
  • 15
  • 148
  • 207