How to scrub photos in place.

-i replaces the originals. The write is atomic, so an interruption cannot corrupt anything — but replacing a file has three consequences, and they are easier to accept before the run than after.

~2 minutes macOS · Linux ScrubPony
// at a glance
  1. Understand what -i costs
  2. Back up anything irreplaceable
  3. Dry-run first
  4. Run with -i -r
Prerequisites
  • ScrubPony installed — see the install page
  • A backup of anything irreplaceable, as before running any tool over a whole library
// step 01

Know the three costs

All three follow from replacing the file rather than editing it. Extended attributes are lost — Finder tags, Spotlight comments and quarantine flags live on the inode, and the rename installs a new one. Hard links are broken, so other links to the old inode keep the unscrubbed content. The mtime is reset, deliberately, because it is metadata too. If any of those matter, use -d instead and move the results into place yourself.

// step 02

Dry-run the tree

Same as always: scrubpony -n -r ~/Pictures writes nothing and shows you the scale of what is about to change.

// step 03

Run it in place

The scrubbed copy is built in a temporary beside each file, fsynced, and renamed over the top in one indivisible step. Kill the process at any moment and the file on disk is either exactly what it was or exactly what it should become — never a partial of either.

$ scrubpony -i -r ~/Pictures
~/Pictures/2026/IMG_4471.jpg: removed 3 segments, 4944 bytes (49.2%), orientation preserved
scrubpony: 834 scrubbed, 366 already clean, 3 not JPEG, 4 skipped, 2 failed
scrubpony: 257 carried GPS coordinates
// step 04

Notice what did not change

A file that would not change is not touched at all — same inode, same mtime. That is decided by comparing the bytes, not by counting segments: a photo scrubbed once still carries our own orientation block, so a second pass drops one segment and writes an identical one back. Only the bytes settle it. Permissions and ownership are carried onto every replacement, so a file that was 0600 does not come back world-readable.

Verify it worked.

  • scrubpony --check -r ~/Pictures exits 0.
  • Portrait photos still display the right way up.
  • File permissions are unchanged — check one with ls -l.
  • No .scrubbed.jpg files appeared: -i replaces rather than adding.

Common questions.

Is it safe to interrupt?

Yes. tests/run_interrupt.sh asserts exactly this by SIGKILLing a 24 MB in-place scrub thirty times at varying moments and checking that nothing but the two legal states ever appears — and that no stray temporary is left behind.

Can I keep the modification times?

No, and there is no flag for it. The mtime is metadata: a scrubbed file still carrying its original capture time defeats part of the purpose.

Can I combine -i with -d?

No — they ask for opposite things and the combination is a usage error, exit code 64.

Are the original bytes gone from the disk?

Not necessarily. The rename guarantees no observer sees a half-written file; it does not guarantee the old blocks are unrecoverable. On a copy-on-write filesystem, an SSD with wear levelling, or anywhere with snapshots or Time Machine, the pre-scrub content may persist.

Next steps.

Get ScrubPony

Strips identifying metadata out of JPEGs without touching a pixel. C99, no dependencies beyond libc, macOS and Linux, MIT-licensed.