4

So I'm working on a script that will accept arguments that are text files, and should output the total number of lines in those files.  For example, if I say

./myScript file1 file2 file3

it will print

10 total

(let us assume that the sum of all the lines from those three files is 10).

I know how to go over all the arguments.  I also know that, to get the number of lines in a file, I would say:

wc -l < fileName

However, how can I make that into an "int" that I can add to some sort of cumulative sum?

3

You can accomplish your goal simply by using cat and a pipeline:

cat "$@" | wc -l

If you really wanted to sum manually, you can do this with awk:

for f in "$@"; do 
    wc -l < "$f"
done | awk '{ sum+=$1 } END { print sum }'

Or if you really wanted to parse the last line of wc, removing the string "total":

wc -l "$@" | awk 'END { print $1 }'
  • Thanks for the response. Can you tell me what your second code does? Not so familiar with awk – Haz Sep 20 '15 at 4:29
  • @haz it adds the first column of each line to the "sum" variable (which starts at 0) and then prints it after all lines have been read. – jordanm Sep 20 '15 at 4:32
2

Building on jordanm’s answer:

1. Pipe all the data through a single instance of wc -l

    if [ "$#" -gt 0 ]
    then
        cat -- "$@" | wc -l
    else
        echo 0
    fi
    
    or
     
    cat -- /dev/null "$@" | wc -l
    
  • Use -- "$@" to guard against filenames beginning with -.
  • Avoid invoking cat with no arguments, as that will cause it to read the standard input.
  • Note that cat a_single_file | something is the classic form of the dreaded Useless Use of Cat, but cat one_or_more_file(s) | something can be OK (although it’s still not ideal).

2. Rely on the fact that wc issues a “total” line

    if [ "$#" -gt 0 ]
    then
        wc -l -- /dev/null "$@" | tail -1
    else
        echo 0 total
    fi
    
    or
     
    wc -l -- /dev/null /dev/null "$@" | tail -1
    
  • Note that wc issues a total line only if it has at least two filename arguments.

3. Use awk without using wc

    if [ "$#" -gt 0 ]
    then
        awk 'END {print NR}' -- "$@"
    else
        echo 0
    fi
    
    or
     
    awk 'END {print NR}' -- /dev/null "$@"
    

Warning:

The above commands will not all produce the same answer if any of the files end with a character other than newline.

1
sed -ne\$= files...

Just hand sed as many filenames as you want in place of files... and, when it has read all of them, it will report the =line-number of the very $last in its input.

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.