Size and Rounding
Scope: -size — what its numbers actually
mean (they are rounded, and the rounding is the
whole story), the suffixes, and the difference
between a file's length and its footprint.
The specimen shelf
Chapter 3 works in tree/sizes/, eleven files
whose byte counts are exact and known:
$ ls -l tree/sizes
total 0
-rw-rw---- 1 root nogroup 0 Oct 20 22:26 s0.bin
-rw-rw---- 1 root nogroup 1 Oct 20 22:26 s1.bin
-rw-rw---- 1 root nogroup 1023 Oct 20 22:26 s1023.bin
-rw-rw---- 1 root nogroup 1024 Oct 20 22:26 s1024.bin
-rw-rw---- 1 root nogroup 1025 Oct 20 22:26 s1025.bin
-rw-rw---- 1 root nogroup 1536 Oct 20 22:26 s1536.bin
-rw-rw---- 1 root nogroup 1048576 Oct 20 22:26 s1m.bin
-rw-rw---- 1 root nogroup 1048577 Oct 20 22:26 s1mplus.bin
-rw-rw---- 1 root nogroup 511 Oct 20 22:26 s511.bin
-rw-rw---- 1 root nogroup 512 Oct 20 22:26 s512.bin
-rw-rw---- 1 root nogroup 513 Oct 20 22:26 s513.bin
One empty file, a run of small ones straddling the 512 and 1024 boundaries, one file of exactly 1 MiB (1048576 bytes), and one a single byte over. Everything this chapter claims is proven against these and nothing else.
The round-up rule
-size does not compare bytes. It converts
the entry's size into whole units of the
size you asked about — rounding up — and
compares that whole number. Ask about
megabytes and every file reports its size as
"how many megabytes does it touch": a
1-byte file touches one megabyte's worth of
the count, so it is size 1M. Proof:
$ find tree/sizes -size 1M
tree/sizes
tree/sizes/s1.bin
tree/sizes/s511.bin
tree/sizes/s512.bin
tree/sizes/s513.bin
tree/sizes/s1023.bin
tree/sizes/s1024.bin
tree/sizes/s1025.bin
tree/sizes/s1536.bin
tree/sizes/s1m.bin
Nine files, from 1 byte to exactly 1 MiB, all
of them "1M". Two more lessons ride along in
that listing. The first line is tree/sizes
itself — the directory, whose own size
also rounds up to one unit. Directories are
entries and this test applies to them; add
-type f when you mean files. And the two
files missing are as instructive as the nine
present: s0.bin, which rounds to zero
units, and s1mplus.bin, which rounds to
two.
The signs behave exactly as the rounding predicts, which is to say not as a beginner expects:
$ find tree/sizes -size -1M
tree/sizes/s0.bin
$ find tree/sizes -size +1M
tree/sizes/s1mplus.bin
-size -1M — "fewer than one unit" — matches
only the empty file: nothing else rounds to
zero. And -size +1M — "more than one unit" —
matches only the file one byte over a
megabyte. The file of exactly 1 MiB is not
+1M; its rounded size is exactly 1, and
more than 1 it is not. This is the single
most-misread test in find: -size +1M does
mean "bigger than a megabyte" in effect, but
only by passing through the rounding — at
every boundary the byte that matters is the
first byte of the next unit.
Honest bytes: the c suffix
When you mean bytes, say bytes. The suffix
c makes the unit one byte, and rounding to
whole bytes is no rounding at all:
$ find tree/sizes -size 1048576c
tree/sizes/s1m.bin
$ find tree/sizes -size +1048576c
tree/sizes/s1mplus.bin
Exact, both ways. The suffixes are:
| Suffix | Unit |
|---|---|
| (none) | 512-byte blocks |
c |
bytes |
w |
2-byte words (a historical survival) |
k |
kibibytes (1024 bytes) |
M |
mebibytes (1048576 bytes) |
G |
gibibytes |
Note that M and k are the binary units —
1024-based — not the decimal ones your disk's
box advertises. The default, no suffix, is
512-byte blocks, a unit nobody thinks in any
more but which still obeys the same rule:
$ find tree/sizes -size 1
tree/sizes
tree/sizes/s1.bin
tree/sizes/s511.bin
tree/sizes/s512.bin
$ find tree/sizes -size 1k
tree/sizes
tree/sizes/s1.bin
tree/sizes/s511.bin
tree/sizes/s512.bin
tree/sizes/s513.bin
tree/sizes/s1023.bin
tree/sizes/s1024.bin
One block covers 1–512 bytes; one kibibyte covers 1–1024; the 1025-byte file needs two of either. Same rounding, smaller units.
Across the whole tree, the rounded test is the right tool for its usual job — "what is actually big here":
$ find tree -size +1M
tree/sizes/s1mplus.bin
tree/big.log
Length is not footprint
One specimen is a liar, on purpose.
tree/big.log reports a length of two and a
half million bytes, and find agrees:
$ ls -l tree/big.log
-rw-rw---- 1 root nogroup 2500000 Oct 20 22:26 tree/big.log
$ find tree -name 'big.log' -printf '%s bytes\n'
2500000 bytes
(-printf is an action that prints in your
own format — %s is the size in bytes. It is
a GNU extension; BSD find doesn't have it,
and chapter 10's recipes note the fallback.)
But ask the disk what the file costs:
$ du -h tree/big.log
0 tree/big.log
Zero. big.log is sparse: its length is
mostly holes — regions no one ever wrote,
which the filesystem records as "nothing
here" instead of storing zeros. ls and
find report the apparent size, the length;
du reports the allocated size, the disk
actually spent. Neither is lying; they are
answering different questions, and the sizes
directory itself (its total 0 in the first
listing) is sparse through and through,
which is how an 11-file shelf of megabyte
specimens costs no disk at all.
So: use -size and -printf to find long
files, use du (chapter 10 of Watching
Your System for Mere Mortals is its home)
to find what is eating the disk — and when
the two disagree wildly about the same file,
you have found a sparse one, which is a
discovery, not an error.
Check: the boundary, in one line each.
-size -1M on tree/sizes returns exactly
s0.bin; -size 1048576c returns exactly
s1m.bin; -size +1048576c returns exactly
s1mplus.bin. If your find returns anything
else, it isn't rounding the way this chapter
describes — and now you know how to check.