142

If I issue the find command as follows:

find . -name *.ear

It prints out:

./dir1/dir2/earFile1.ear
./dir1/dir2/earFile2.ear
./dir1/dir3/earFile1.ear

I want to 'print' the name and the size to the command line:

./dir1/dir2/earFile1.ear  5000 KB
./dir1/dir2/earFile2.ear  5400 KB
./dir1/dir3/earFile1.ear  5400 KB
Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
Brian
  • 13,249
  • 9
  • 54
  • 80

17 Answers17

152
find . -name '*.ear' -exec ls -lh {} \;

just the h extra from jer.drab.org's reply. saves time converting to MB mentally ;)

shyam
  • 8,684
  • 4
  • 27
  • 42
  • 12
    This version will exec "ls" process for each file. If you have many files (say, over a thousand) you better optimize that by either: `find . -name '*.ear' -exec ls -lh {} + \;` (GNU extension) or `find . -name '*.ear' -print0 | xargs -0 ls -lh`. Also you may like to add `-type f` if you're only interested in files (or add `-d` to ls if you want directories themselves included without their contents). – ash108 Mar 24 '12 at 14:36
  • 2
    Your answer does not exclude directories, so you will end up running ls on directories as well, which clearly is not the right thing to do. – Faheem Mitha Nov 07 '14 at 10:08
  • 2
    This is a really inefficient way of doing things - and unfortunately ash108's comments are also not ideal. It's much better to use the -printf option to find. – oskarpearson May 19 '15 at 09:47
  • 1
    dmazzoni's answer is much more efficient because it avoids a fork+exec on every file (100x faster on my machine). I had to change %k to %s. @FaheemMitha: you can add options like `-type f` to only count regular files. – Mr Fooz Sep 29 '16 at 23:19
  • @FaheemMitha easy solution is `find . -name "*.ear" -type f` for files. `-type d` works for directories. – fIwJlxSzApHEZIl Oct 20 '16 at 17:38
  • This also works: `find . -type f -name "*.bfc" -exec du -s {} \;` – skeetastax Aug 06 '20 at 03:43
136

You need to use -exec or -printf. Printf works like this:

find . -name *.ear -printf "%p %k KB\n"

-exec is more powerful and lets you execute arbitrary commands - so you could use a version of 'ls' or 'wc' to print out the filename along with other information. 'man find' will show you the available arguments to printf, which can do a lot more than just filesize.

[edit] -printf is not in the official POSIX standard, so check if it is supported on your version. However, most modern systems will use GNU find or a similarly extended version, so there is a good chance it will be implemented.

Leigh Caldwell
  • 9,748
  • 4
  • 23
  • 31
  • It looks like your example is more precise, but I can't seem to get the example to work on Solaris 10. – Brian Sep 15 '08 at 17:21
  • 1
    I'm afraid Solaris find does not support -printf at all: http://jrwren.wrenfam.com/blog/2006/10/07/solaris-find-sucks/ http://www.cs.bgu.ac.il/~arik/usail/man/solaris/find.1.html You could install GNU find if you can be bothered, otherwise you need to use exec or | as suggested by others. – Leigh Caldwell Sep 15 '08 at 17:27
  • 1
    +1 This seems more cleaner. To format the output I would prefer add `column` command. `find . -name *.ear -printf "%p %k KB\n" | column -t` – Amol Dec 06 '12 at 09:53
  • 1
    This answer is a much more correct way to do it than the accepted answer – menacingly Apr 26 '15 at 14:12
  • 3
    The `-printf` option doesn't work in OS X either. See http://stackoverflow.com/questions/752818/find-lacks-the-option-printf-now-what. – abeboparebop Jun 07 '16 at 09:02
  • Works great on recent Ubuntu! – Gringo Suave Mar 22 '19 at 22:12
39

A simple solution is to use the -ls option in find:

find . -name \*.ear -ls

That gives you each entry in the normal "ls -l" format. Or, to get the specific output you seem to be looking for, this:

find . -name \*.ear -printf "%p\t%k KB\n"

Which will give you the filename followed by the size in KB.

Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
Michael Cramer
  • 4,882
  • 1
  • 19
  • 16
29

Using GNU find, I think this is what you want. It finds all real files and not directories (-type f), and for each one prints the filename (%p), a tab (\t), the size in kilobytes (%k), the suffix " KB", and then a newline (\n).

find . -type f -printf '%p\t%k KB\n'

If the printf command doesn't format things the way you want, you can use exec, followed by the command you want to execute on each file. Use {} for the filename, and terminate the command with a semicolon (;). On most shells, all three of those characters should be escaped with a backslash.

Here's a simple solution that finds and prints them out using "ls -lh", which will show you the size in human-readable form (k for kilobytes and M for megabytes):

find . -type f -exec ls -lh \{\} \;

As yet another alternative, "wc -c" will print the number of characters (bytes) in the file:

find . -type f -exec wc -c \{\} \;
Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
dmazzoni
  • 12,416
  • 4
  • 37
  • 34
  • 1
    +1 Except for having omitted `-name '*.ear'` in the examples, this should be the #1 answer. It answers the question precisely, explains the meaning of the syntax, and gives multiple alternatives. – OsakaWebbie Jul 28 '17 at 06:40
  • 1
    this should be accepted answer as it doesn't run new command for every line, thus it is much more faster than the currently accepted one from shyam – jirislav Feb 05 '18 at 23:02
  • 1
    Indeed this should be the right answer. Also, `find . -type f -printf '%k KB\t %p\n'` i.e., printing the file size first, will most likely be a nicer output in terms of formatting due to the alignment. – myradio Jun 25 '18 at 12:41
10
find . -name '*.ear' -exec du -h {} \;

This gives you the filesize only, instead of all the unnecessary stuff.

kenorb
  • 137,499
  • 74
  • 643
  • 694
  • `wc` works for this just better, if you need the size in bytes. – Alex Jul 18 '17 at 13:32
  • *This gives you the filesize only,* No, this gives disk usage, not file size. They are note the same. The value this returns will be wrong for any filesystem that supports compression. – Andrew Henle May 18 '21 at 02:17
4

Why not use du -a ? E.g.

find . -name "*.ear" -exec du -a {} \;

Works on a Mac

sietschie
  • 7,017
  • 2
  • 31
  • 54
Andreas
  • 1
  • 1
  • Based on the [du man page](https://man7.org/linux/man-pages/man1/du.1.html) ` -a, --all write counts for all files, not just directories ` I think you want to use -h ` -h, --human-readable print sizes in human readable format (e.g., 1K 234M 2G) ` – Craig Nov 05 '21 at 15:23
4

Awk can fix up the output to give just what the questioner asked for. On my Solaris 10 system, find -ls prints size in KB as the second field, so:

% find . -name '*.ear' -ls | awk '{print $2, $11}'
5400 ./dir1/dir2/earFile2.ear
5400 ./dir1/dir2/earFile3.ear
5400 ./dir1/dir2/earFile1.ear

Otherwise, use -exec ls -lh and pick out the size field from the output. Again on Solaris 10:

% find . -name '*.ear' -exec ls -lh {} \; | awk '{print $5, $9}'
5.3M ./dir1/dir2/earFile2.ear
5.3M ./dir1/dir2/earFile3.ear
5.3M ./dir1/dir2/earFile1.ear
tpgould
  • 1,746
  • 10
  • 10
4

Try the following commands:

GNU stat:

find . -type f -name *.ear -exec stat -c "%n %s" {} ';'

BSD stat:

find . -type f -name *.ear -exec stat -f "%N %z" {} ';'

however stat isn't standard, so du or wc could be a better approach:

find . -type f -name *.ear -exec sh -c 'echo "{} $(wc -c < {})"' ';'
kenorb
  • 137,499
  • 74
  • 643
  • 694
3

I struggled with this on Mac OS X where the find command doesn't support -printf.

A solution that I found, that admittedly relies on the 'group' for all files being 'staff' was...

ls -l -R | sed 's/\(.*\)staff *\([0-9]*\)..............\(.*\)/\2 \3/'

This splits the ls long output into three tokens

  1. the stuff before the text 'staff'
  2. the file size
  3. the file name

And then outputs tokens 2 and 3, i.e. output is number of bytes and then filename

8071 sections.php
54681 services.php
37961 style.css
13260 thumb.php
70951 workshops.php
Peter O.
  • 30,765
  • 14
  • 76
  • 91
Mike M
  • 1
  • 2
2

This should get you what you're looking for, formatting included (i.e. file name first and size afterward):

find . -type f -iname "*.ear" -exec du -ah {} \; | awk '{print $2"\t", $1}'

sample output (where I used -iname "*.php" to get some result):

./plugins/bat/class.bat.inc.php  20K
./plugins/quotas/class.quotas.inc.php    8.0K
./plugins/dmraid/class.dmraid.inc.php    8.0K
./plugins/updatenotifier/class.updatenotifier.inc.php    4.0K
./index.php      4.0K
./config.php     12K
./includes/mb/class.hwsensors.inc.php    8.0K
adriano72
  • 417
  • 5
  • 9
2

Just list the files (-type f) that match the pattern (-name '*.ear) using the disk-usage command (du -h) and sort the files by the human-readable file size (sort -h):

find . -type f -name '*.ear' -exec du -h {} \; | sort -h

Output

5.0k  ./dir1/dir2/earFile1.ear
5.4k  ./dir1/dir2/earFile2.ear
5.4k  ./dir1/dir3/earFile1.ear
Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
Craig
  • 2,068
  • 3
  • 22
  • 37
1
$ find . -name "test*" -exec du -sh {} \;
4.0K    ./test1
0       ./test2
0       ./test3
0       ./test4
$

Scripter World reference

skynet
  • 9,828
  • 5
  • 42
  • 52
scripter
  • 1
  • 1
1

You could try this:

find. -name *.ear -exec du {} \;

This will give you the size in bytes. But the du command also accepts the parameters -k for KB and -m for MB. It will give you an output like

5000  ./dir1/dir2/earFile1.ear
5400  ./dir1/dir2/earFile2.ear
5400  ./dir1/dir3/earFile1.ear
Yaba
  • 5,959
  • 8
  • 37
  • 44
1
find . -name "*.ear" | xargs ls -sh
Igor
  • 31,955
  • 14
  • 75
  • 111
killdash10
  • 708
  • 5
  • 12
0

If you need to get total size, here is a script proposal

#!/bin/bash
totalSize=0

allSizes=`find . -type f -name *.ear -exec stat -c "%s" {} \;`

for fileSize in $allSizes; do
    totalSize=`echo "$(($totalSize+$fileSize))"`
done
echo "Total size is $totalSize bytes"
Damien C
  • 827
  • 1
  • 9
  • 16
0
find . -name "*.ear" -exec ls -l {} \;
BenMorel
  • 31,815
  • 47
  • 169
  • 296
Jeremy Weathers
  • 2,535
  • 1
  • 16
  • 24
0

You could try for loop:

for i in `find . -iname "*.ear"`; do ls -lh $i; done
NILESH KUMAR
  • 375
  • 3
  • 7