Limit report and trees to given paths (closes #174)
check / check (push) Canceled after 0s

report and trees take optional PATH operands and use only the records
at or below them. Operands are made absolute and cleaned as text, never
looked up on the filesystem. With operands, trees reports only
directories at or below an operand: a directory above them holds
unused files, so its digest neither gets reported nor suppresses its
children's group. The summary still counts every record read.

Model: opus-5-5
This commit is contained in:
sneak committed 2026-11-11 04:01:34 +00:00
1 parent 6c529fcc6d
commit 97a02da837
9 files changed
+330 -58

No files matched your search

+49 -18
View File
@@ -43,7 +43,9 @@ as opposed to a directory, a symlink or a device node. A symlink is a file that
holds the path of another file and stands in for it. A device node is a file
that stands for a piece of hardware, such as a disk or a terminal. `report`
prints the file-level duplicates. `trees` prints the duplicate directory trees.
`info` prints the database's path, size and record count.
Both cover the whole database, or only the paths given after them, as in
`sfdupes report /srv/photos`. `info` prints the database's path, size and record
count.
The database is `/var/lib/sfdupes/db.sqlite` unless `SFDUPES_DATABASE` names
another file. The first `scan` creates it.
@@ -253,8 +255,8 @@ In order:
```
sfdupes scan [--workers N] [-x] [--no-default-excludes] PATH...
sfdupes report > dupes.tsv
sfdupes trees > dupetrees.tsv
sfdupes report [PATH...] > dupes.tsv
sfdupes trees [PATH...] > dupetrees.tsv
sfdupes info
sfdupes dwim
sfdupes --version
@@ -653,12 +655,12 @@ and `scan` leaves it ignored.
### `report` mode
`report` reads every record from the database. It takes no positional arguments.
A positional argument is anything on the command line that is not a flag, such
as the paths `scan` takes. `report` never touches the scanned filesystem. It
neither stats nor opens any path in the records. It reads the database and
writes to stdout and stderr, and nothing else. Its output is the same whether or
not the scanned filesystem is still mounted.
`report` reads every record from the database. It takes optional `PATH`
operands. With none, it uses every record. With one or more, it uses only the
records at or below them (see "Report paths"). `report` never touches the
scanned filesystem. It neither stats nor opens any path in the records. It reads
the database and writes to stdout and stderr, and nothing else. Its output is
the same whether or not the scanned filesystem is still mounted.
Processing:
@@ -681,6 +683,26 @@ with one signature come together, and so do the records of one size. So `report`
holds only the duplicate groups of the size it is reading. Once it reaches a
smaller size, it writes them, ordered by `first` path.
#### Report paths
`report` and `trees` take the same `PATH` operands:
- A record is used when its path is an operand or lies below one. `/srv/photos`
covers `/srv/photos/x` but not `/srv/photos2/x`.
- The records used are grouped, ordered and totalled as they are without
operands. A copy outside the operands is not reported. With copies `/a/f`,
`/srv/photos/x` and `/srv/photos/y`, `sfdupes report /srv/photos` prints one
row, `/srv/photos/x` and `/srv/photos/y`.
- A relative operand is joined to the working directory as `pwd -P` prints it.
- Each operand is then cleaned as text, as `realpath -ms` prints it. Its `.`
elements and repeated or trailing slashes are dropped. Each `..` drops the
element before it.
- No operand is looked up on the filesystem. A symlink in an operand is not
followed, and an operand need not exist. The records hold real paths (see
"Operands"), so an operand that passes through a symlink matches no record.
- An operand that matches no record is not an error. The report then has no
rows.
#### Report output format
The report is TSV (tab-separated values) on stdout. It holds a header line, then
@@ -708,7 +730,8 @@ Grouping and ordering use the stored path. The warnings about skipped paths that
The summary line on stderr gives:
- the records read;
- the records read, which are all the records in the database, with or without
operands;
- the duplicate groups;
- the dupe files, which is the number of rows;
- the reclaimable bytes, the sum of `size` over all rows.
@@ -719,11 +742,12 @@ report: 14 records read, 4 duplicate groups, 7 dupe files, 10.0 KiB reclaimable
### `trees` mode
`trees` reads the same database as `report` and takes no positional arguments.
It reports whole duplicate directory trees. Two directories are duplicate trees
when they hold the same relative paths, and each path holds a file with the same
signature in both. Like `report`, it never touches the scanned filesystem. It
rebuilds the directory tree from the paths in the records, split on `/`.
`trees` reads the same database as `report` and takes the same `PATH` operands
(see "Report paths"). It reports whole duplicate directory trees. Two
directories are duplicate trees when they hold the same relative paths, and each
path holds a file with the same signature in both. Like `report`, it never
touches the scanned filesystem. It rebuilds the directory tree from the paths in
the records, split on `/`.
Definitions:
@@ -750,6 +774,10 @@ Processing:
directories that all have the same digest. The parents' group, or an
ancestor's, already implies it. A group is always reported when it holds
sibling directories, or when its members' parents have different digests.
- With operands, `trees` builds the tree from the records it uses. It reports
only directories at or below an operand. A directory above every operand holds
files that are not used, so its digest does not describe it. Such a directory
is never reported and never implies a group of its children.
- Within a group, paths are sorted in byte order. The first is `first`, and
every other path is a `dupe`.
- Groups are ordered by total tree size, largest first, then by `first` path.
@@ -799,7 +827,8 @@ directory's path is `/`.
The summary line on stderr gives:
- the records read;
- the records read, which are all the records in the database, with or without
operands;
- the duplicate-tree groups;
- the dupe trees, which is the number of rows;
- the reclaimable bytes, the sum of `size` over all rows.
@@ -812,7 +841,9 @@ trees: 14 records read, 1 duplicate tree groups, 1 dupe trees, 3.0 KiB reclaimab
`dwim`, short for "do what I mean", scans a new machine and reports its
duplicate trees in one command. It takes no positional arguments and no flags of
its own. Like `scan`, it should run as root, so that it can read every file.
its own. A positional argument is anything on the command line that is not a
flag, such as the paths `scan` takes. Like `scan`, it should run as root, so
that it can read every file.
`dwim` runs what `sfdupes scan /` runs with no flags. The walk skips the default
excludes and crosses into other filesystems. `--workers` keeps its default. The
@@ -1198,7 +1229,7 @@ showing the count it stopped at.
`--workers abc`;
- `scan` with no operand;
- `--workers` below 1;
- `report`, `trees`, `info` or `dwim` with a positional argument.
- `info` or `dwim` with a positional argument.
A fatal error is reported on stderr, starting with `sfdupes:`. A failed write to
stdout, such as a full disk, is reported the same way. Two cases never reach