Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

I'm using find to search through all subdirectories and current directory to find all .py files, and then run wc -l to find number of lines. However, when I use find with wc, the Total field is left off, unlike when I run wc by itself. Does anyone know why this is happening?

find . -name \*.py -exec wc -l {} \;
  187 ./check.py
   43 ./file.py
   33 ./mitch.py
       ...
 1014 ./serve.py
   41 ./test_scripts/line_graph.py
   39 ./welcome.py

But no total, but when I run wc -l *.py in a directory I get a total:

wc -l *.py
 187 check.py
  43 file.py
  94 log_com.py
 154 log_results.py
  33 mitch.py
1014 serve.py
  39 welcome.py
1564 total
share|improve this question

2 Answers 2

up vote 1 down vote accepted

wc only outputs a Total value when it's called with more than one file as arguments.

From the GNU manual:

If more than one file is given, wc prints a final line containing the cumulative counts, with the file name total.

In your case, you cannot get a Total output, since you invoke wc once for each file found, so every subsequent wc call does not know about the previous one.


If you still want the total count, you can use the globstar option in Bash to recurse into directories and list .py files:

shopt -s globstar
wc -l **/*.py

Or, as grawity suggests, with GNU find's -exec command {} + option, to have find substitute all found paths in {}, instead of calling each one individually (although there is a limit to the number of files it can substitute, just like with the glob approach).

share|improve this answer
    
Ah that makes sense. So how would I go about doing this instead? –  taronish4 Aug 28 '13 at 17:39
    
Updated my post. The most bullet-proof way would be to use awk– see grawity's answer. –  slhck Aug 28 '13 at 17:45

There is no total field because there's only one file.

With the -exec command {} ; action, find runs command once for every file, with only a single argument added each time. So there is nothing that each wc invocation could calculate the total from.

You'd have to use -exec command {} + if you have GNU find; otherwise you'll need to pipe the list of files to xargs command.

(In this answer I'm not going to bother with the usual -print0 suggestion, because if you don't have GNU find, you won't have -print0 or even GNU xargs either. However, if your version of xargs does support -d '\n', use that, because the default way xargs parses input isn't very safe.)

Note that this might still result in multiple wc invocations, because most operating systems (except maybe Hurd) have a limit on the maximum command-line length and/or maximum number of arguments to a single command, which a large number of files might exceed. @slhck's suggestion of using **/*.py would also hit the same limit (early Unixes having had very low limits is why xargs was created in the first place).

Another alternative is to use awk for the final calculation:

find ... | awk '$2 != "total" {sum += $1; print}
                END {printf "%7d total\n", sum}'
share|improve this answer
    
Out of curiosity, have you hit the limit in practice already? (Of course I think it should be mentioned regardless.) –  slhck Aug 28 '13 at 17:44
    
@slhck: Once – when trying to remove everything from pacman's downloaded package cache. (I had mistakenly used an absolute path in the command, so that doubled the length of every path.) I've gotten used to find -delete as an alternative to rm -rf * since then. –  grawity Aug 28 '13 at 17:46

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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