165

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,738
  • 21
  • 105
  • 131
Brian
  • 13,412
  • 10
  • 56
  • 82

17 Answers17

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

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

Jules G.M.
  • 3,624
  • 1
  • 21
  • 35
shyam
  • 9,134
  • 4
  • 29
  • 44
  • 16
    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
  • 3
    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
  • This answer corners the output to only show Gigs or the original format. Also displays too much information. Op's examples only show file path and size. You can use the following to choose whatever size you want. `find . -name '*.ear' -exec ls -s --block-size=G {} \;` for gigs, and `find . -name '*.ear' -exec ls -s --block-size=M {} \;` for megs. – Dave Aug 30 '22 at 12:38
147

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
  • 10,426
  • 4
  • 25
  • 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
53

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,738
  • 21
  • 105
  • 131
Michael Cramer
  • 5,080
  • 1
  • 20
  • 16
31

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,738
  • 21
  • 105
  • 131
dmazzoni
  • 12,866
  • 4
  • 38
  • 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
9
find . -name '*.ear' -exec du -h {} \;

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

kenorb
  • 155,785
  • 88
  • 678
  • 743
  • `wc` works for this just better, if you need the size in bytes. – Alex Jul 18 '17 at 13:32
  • 1
    *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
7

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,738
  • 21
  • 105
  • 131
Craig
  • 2,286
  • 3
  • 24
  • 37
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
  • 155,785
  • 88
  • 678
  • 743
3

Why not use du -a ? E.g.

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

Works on a Mac

sietschie
  • 7,425
  • 3
  • 33
  • 54
Andreas
  • 1
  • 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
  • 1
    Because this prints disk usage, which is not the same as file size. – DanielSmedegaardBuus Sep 11 '22 at 23:57
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.
  • 32,158
  • 14
  • 82
  • 96
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
  • 6
  • 9
1
$ find . -name "test*" -exec du -sh {} \;
4.0K    ./test1
0       ./test2
0       ./test3
0       ./test4
$

Scripter World reference

skynet
  • 9,898
  • 5
  • 43
  • 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,979
  • 8
  • 38
  • 44
1
find . -name "*.ear" | xargs ls -sh
Igor
  • 33,276
  • 14
  • 79
  • 112
killdash10
  • 706
  • 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
  • 969
  • 1
  • 10
  • 16
0
find . -name "*.ear" -exec ls -l {} \;
BenMorel
  • 34,448
  • 50
  • 182
  • 322
Jeremy Weathers
  • 2,556
  • 1
  • 16
  • 24
-1

You could try for loop:

for i in `find . -iname "*.ear"`; do ls -lh $i; done
NILESH KUMAR
  • 413
  • 5
  • 10