30

I was trying to use sed to count all the lines based on a particular extension.

find -name '*.m' -exec wc -l {} \; | sed ...

I was trying to do the following, how would I include sed in this particular line to get the totals.

Berlin Brown
  • 11,504
  • 37
  • 135
  • 203

8 Answers8

57

You may also get the nice formatting from wc with :

wc `find -name '*.m'`
Emmanuel BERNAT
  • 793
  • 6
  • 17
18

Most of the answers here won't work well for a large number of files. Some will break if the list of file names is too long for a single command line call, others are inefficient because -exec starts a new process for every file. I believe a robust and efficient solution would be:

find . -type f -name "*.m" -print0 | xargs -0 cat | wc -l

Using cat in this way is fine, as its output is piped straight into wc so only a small amount of the files' content is kept in memory at once. If there are too many files for a single invocation of cat, cat will be called multiple times, but all the output will still be piped into a single wc process.

Daniel James
  • 3,899
  • 22
  • 30
  • 2
    Or use the standard/portable form instead: `find . -type f -name '*.m' -exec cat {} + | wc -l`. – Stephane Chazelas Sep 05 '16 at 10:06
  • how to modify this to print out total lines for each file among with the file name? – loretoparisi Sep 20 '18 at 09:17
  • 1
    @loretoparisi Then trivially run `-exec wc -l {} +` instead of `-print0 | xargs ...`. Using `+` with `-exec` might end up running more than one instance of `wc -l` and then you will need to sum the totals from each run for the overall total. Or if you don't care about totals, just remove those lines with `grep -v`; or, use `-exec wc -l {} \;` to run a separate instance of `wc` on each file, at a somewhat higher processing cost. – tripleee Jan 11 '23 at 10:47
6

You can cat all files through a single wc instance to get the total number of lines:

find . -name '*.m' -exec cat {} \; | wc -l
sth
  • 222,467
  • 53
  • 283
  • 367
5

On modern GNU platforms wc and find take -print0 and -files0-from parameters that can be combined into a command that count lines in files with total at the end. Example:

find . -name '*.c' -type f -print0 | wc -l --files0-from=-
Stephane Chazelas
  • 5,859
  • 2
  • 34
  • 31
4

you could use sed also for counting lines in place of wc:

 find . -name '*.m' -exec sed -n '$=' {} \;

where '$=' is a "special variable" that keep the count of lines

EDIT

you could also try something like sloccount

dfa
  • 114,442
  • 31
  • 189
  • 228
  • find . -name '*.m' -exec sed -n 'where $=' {} \; Is this it? – Berlin Brown Sep 11 '09 at 17:36
  • That is not the total though, added together. – Berlin Brown Sep 11 '09 at 17:37
  • OK, I ended up with this. $ find . -name '*.m' -exec sed -n '$=' {} \; | sum - 22696 1 – Berlin Brown Sep 11 '09 at 17:38
  • 3
    __where '$=' is a "special variable" that keep the count of lines__. You jest sire! `$=` represents an address and a command. The `$` is last line, the command `=` is current line number, in conjunction with `-n` switch which supresses pattern space printout. The outcome is it __counts__ the number of lines fed to it. – potong Dec 13 '11 at 13:45
  • @dfa Thanks. How to print the filename before the count? – loretoparisi Sep 20 '18 at 09:13
3

Hm, solution with cat may be problematic if you have many files, especially big ones.

Second solution doesn't give total, just lines per file, as I tested.

I'll prefer something like this:

find . -name '*.m' | xargs wc -l | tail -1

This will do the job fast, no matter how many and how big files you have.

igustin
  • 1,110
  • 8
  • 8
  • If there are too many files for a single command line, xargs will chunk them and this will only give the total for the final chunk. – Daniel James Jan 07 '12 at 07:16
1

sed is not the proper tool for counting. Use awk instead:

find . -name '*.m' -exec awk '{print NR}' {} +

Using + instead of \; forces find to call awk every N files found (like with xargs).

marco
  • 4,455
  • 1
  • 23
  • 20
1

For big directories we should use:

find . -type f -name '*.m' -exec sed -n '$=' '{}' + 2>/dev/null | awk '{ total+=$1 }END{print total}' 

# alternative using awk twice
find . -type f -name '*.m' -exec awk 'END {print NR}' '{}' + 2>/dev/null | awk '{ total+=$1 }END{print total}'