dctl size
Show total size and object count.
Synopsis#
dctl size is the cheapest question in the listing family and the one most often
asked from a script: two numbers over a subtree.
dctl size vault:photos
Total objects: 1,234
Total size: 1.44 GiB (1546188226 bytes)It measures the same scope every other listing verb uses, and shares the code
that decides that scope, so dctl size --include "*.CR3" and
dctl ls --include "*.CR3" | wc -l agree by construction. A pair of commands
that disagreed about the same vault would leave a user no way to tell which one
was lying.
Two renderings of the same number#
The text report prints the rounded human figure and the exact byte count,
because they answer different questions. 1.44 GiB is what a person reads;
1546188226 is what gets subtracted from a quota, and a rounded figure quietly
loses up to five per cent of it. The exact figure carries no thousands
separators and no unit ladder — it is there to be pasted into arithmetic. The
object count is grouped (1,234) because it is only ever read, never computed
with.
--units decimal changes the rounded figure to the convention providers bill in
(1.55 GB); the exact byte count never changes, since a byte is a byte.
Under --json (or --format json) the shape is:
{
"count": 1234,
"bytes": 1546188226,
"measured_bytes": 1546188226,
"unmeasured": 0,
"sizes": "plaintext"
}and under --format json-lines the same object on a single line. count and
bytes are rclone's size --json shape, lower case, so a script that already
reads .count and .bytes keeps working. Both values are exact: rounding
belongs in the text rendering and nowhere else, and a machine has no use for a
rounded number and every use for a stable one.
When the total cannot be computed#
A vault's sizes live in its index, and a row can lack one.
dctl index rebuild reads each object's own header for the size, so a rebuilt
index normally carries them all; a row that is still unmeasured belongs to an
object whose header could not be read back at all, which the rebuild counts and
exits 6 over.
bytes is then null, not 0:
{ "count": 1234, "bytes": null, "measured_bytes": 0, "unmeasured": 1234, "sizes": "plaintext" }Total objects: 1,234
Total size (plaintext): at least 0 B (0 bytes)
Unmeasured objects: 1,234
warning: some objects carry no recorded size, so this figure is a lower bound…bytes— the exact total, andnullwhen even one object in scope has no recorded size. A capacity monitor reading.bytesafter a rebuild used to be told a forty-terabyte vault held0, which it cannot tell from an empty one. Anullbreaks that monitor's arithmetic loudly, at the moment it would otherwise have reported a fiction.measured_bytes— always a number: the sum of the objects that did have a recorded size. Whenbytesisnullthis is the honest lower bound, and it is the figure the text report prints. Whenbytesis notnullthe two are equal.unmeasured— how many objects in scope had no recorded size, which is the reasonbytesisnull.
A genuinely empty file is measured: it has a recorded size of zero, and it does not make the total unknown. The two states are different facts and the shape keeps them apart.
A read does not fill those sizes in — cat, hashsum and a whole scrub all
leave the row exactly as unmeasured as they found it. The remedy is
dctl index rebuild, which reads the header each size lives in.
A row still unmeasured after that belongs to an object whose header could not be
read back at all, and the rebuild names how many.
An empty scope reports zeroes rather than nothing — Total objects: 0 /
Total size: 0 B (0 bytes). "Zero objects" is an answer; silence is not. That
zero is a measurement: an empty scope really does hold nothing, which is why it
is a number here and null in the unmeasured case above. Unlike its siblings,
size prints no "nothing matched" note, because the zeroes already say it.
Memory#
Two 64-bit integers, whatever the vault holds. This is the command that proves
the streaming pipeline is real: counting ten million objects must not need ten
million anything (PLAN.md §16.2). Entries arrive one page of 1000 at a time and
are added and dropped. The additions saturate rather than wrap — a vault whose
total overflows a u64 is not something DCTL will meet, and a saturated value
would at least be visibly wrong where a wrapped one would look plausible.
Scope#
Identical to ls, and worth restating because the whole value of
this command is that the number matches:
--includeand--excludeare repeatable globs; exclusion wins, and--includenarrows whatever survived.*stops at a path separator,**crosses one.- A pattern with a leading
/is anchored at the listing root; a pattern with no/at all matches the file name at any depth; anything else matches the root-relative path or any component-aligned suffix of it. --min-size/--max-sizeaccept10G,1.5MiBoroff, and apply to objects.--max-depth Ncounts from the listing root, one-based;-1is unlimited.--filter-fromand--files-fromare honoured, by the same rule enginedctl copyuses. A rule file that cannot be read or parsed is a usage error (exit 1) naming the file and the line, never a run with the rules dropped: a total computed from silently-dropped rules is a wrong number that looks right, and capacity decisions get made on these numbers.
The positional argument is REMOTE:PATH, falling back to --remote /
DCTL_REMOTE. \\nas\share is a local path on every platform, and C:\data
and d:/data are local where drives exist — both checked before the colon split.
Off Windows those two name the remotes C and d, as they do in rclone. The
path half is canonicalised
(/-separated, NFC, no . components, no trailing slash) and a .. component
is rejected.
What is measured, and what is not#
size reports plaintext bytes: the sum of the sizes the index recorded for
the objects in scope. That is not the same as what the provider bills for.
Ciphertext carries per-chunk AEAD tags and per-object headers, a vault-wrapped
remote stores its own metadata, and a provider may retain old versions and
abandoned multipart uploads that no longer appear in any listing. Use
dctl about for the provider's own view of usage and quota,
and dctl cleanup to remove what a listing no longer shows.
Writes, commits, and why zero is dangerous#
size writes nothing, commits nothing and never sends bytes to a provider, so a
checksum mismatch is not among its failure modes. What it does carry is the
reporting half of the verified-write contract: an object contributes to these
totals only after its bytes were checksum-verified at the destination and
durably committed to the encrypted index (PLAN.md §6), so a half-finished
upload is never counted as stored.
And a run that could not reach the index fails with a non-zero exit code
rather than reporting zero. A reported zero would be indistinguishable from an
empty vault, and "the backup is empty" is a conclusion people act on — by
re-uploading, or by pruning something else. --dry-run changes neither the
output nor the exit code.
Status in this build#
dctl size reads a vault, and reads a local directory. Spec parsing, the
filters, the streaming accumulation and both output shapes are
implemented, and so is the index read this page once said was missing:
dctl size vault: totals the stored objects and dctl size ./src totals a
local tree. Earlier revisions quoted an exit-7 reading the object index is not implemented error that no build now produces.
The one gap left is shared with the rest of the listing family: a local path
that does not exist produces a zero total and exit 0 rather than exit 3
(dir_not_found). See dctl ls for why that matters before a script
branches on it.
size is the sharpest case in the family, because it is the one whose empty
answer is a number. dctl size ./nope prints Total objects: 0 and exits 0,
and unlike the other five it prints no -v note at all — nothing on any stream
distinguishes "this path holds nothing" from "this path is not there".
dctl size [REMOTE:PATH] [flags]Examples#
The reports below are what the renderer produces, and every one of them runs in this build.
Measure a whole vault:
dctl size vault:
Total objects: 8,417
Total size: 231.6 GiB (248686112768 bytes)Measure one subtree, in the convention the provider bills in. The rounded figure
follows --units; the exact byte count never does:
dctl size b2prod:bucket/media --units decimal
Total objects: 6,102
Total size: 248.7 GB (248686112768 bytes)Measure only what a filter selects. The same flags on dctl ls list exactly the
objects counted here:
dctl size vault:photos --include "*.CR3" --min-size 8MFeed the exact numbers to a script. The field names are rclone's, so an existing
consumer of rclone size --json keeps working:
dctl size vault:photos --json | jq '.bytes'Track a vault's growth from a cron job, one line per run. json-lines gives a
compact single-line record that appends cleanly to a log:
dctl size vault: --format json-lines >> capacity.jsonlA rule file and an exact path list both narrow what is measured, through the
same engine copy and sync use — so a capacity figure describes exactly the
objects a transfer under those rules would move:
$ dctl size archive: --files-from list.txt
Total objects: 2
Total size (plaintext): 18 B (18 bytes)A file that cannot be read or parsed is a usage error rather than a run with the rules dropped: a capacity number computed from ignored rules is a wrong number that looks right.
A Windows path is local on every platform, so it is measured as a directory
rather than resolved against the configured remotes. C: is a drive letter,
never a remote named C, which would instead fail with unknown remote 'C' and
exit 7:
dctl size C:\Users\mx\Pictures
Total objects: 1
Total size (stored): 2.10 MiB (2202009 bytes)On a machine where that path does not exist this prints Total objects: 0 and
exits 0 — with no note on any stream. See Status in this build.
Options#
-h, --help help for sizesize declares no flags of its own; everything that shapes the measurement is a
global flag, so its totals cannot drift from what the other listing verbs show.
The positional argument is [REMOTE:PATH], optional, falling back to
--remote. -V, --version is propagated to every subcommand.
Options inherited from parent commands#
Every global flag is accepted. The relevant ones are the filters
--include / --exclude / --min-size / --max-size / --max-depth /
--filter-from / --files-from, --units (the rounded figure
only), --format / --json (which replace the two text lines with the
{"count","bytes"} object), --quiet, and --config / --index / the
--password* group. See ../GLOBAL_FLAGS.md for the full
list.
Exit codes#
| Code | Name | When |
|---|---|---|
| 0 | success | The totals were printed, including a legitimate zero. Not reachable in this build. |
| 1 | usage | No path and no --remote; an illegal or too-short remote name; a .. component; a malformed pattern or size value; an unknown flag or a second positional. |
| 2 | uncategorised | A stdout write failed for a reason other than a broken pipe. A broken pipe is success. |
| 5 | temporary_error | The provider could not be reached and the retry budget was exhausted. Needs the engine work below. |
| 7 | fatal_error | Returned by every complete invocation in this build, by a local target, and by --filter-from/--files-from. |
| 22 | vault_locked | Wrong password or second factor, or a damaged envelope. Needs the engine work below. |
| 23 | index_error | The encrypted index or its journal could not be read. Needs the engine work below. |
| 25 | cancelled | Ctrl-C or SIGTERM. A partial total is never printed as if it were final. |
In this build only 1, 2, 7 and 25 are reachable. A zero total is only ever printed on exit 0, so a script must check the exit code before believing one. See ../EXIT_CODES.md for the full contract.
See also#
- dctl ls — the objects behind the count, over the same scope.
- dctl lsd — the same totals broken down per directory.
- dctl tree — its stderr footer reports the same byte total for the drawn subtree.
- dctl about — the provider's own usage and quota figures, which include ciphertext overhead and retained versions.
- dctl cleanup — remove abandoned uploads and old versions that a listing no longer shows but the bill still does.