Bash rename loop silently overwrote 21 user files via failed BASH_REMATCH expansion
Summary
Claude Code (Opus 4.7, 1M context) wrote and executed a multi-file mv rename loop using [[ "$f" =~ regex ]] with ${BASH_REMATCH[1]} etc. for capture extraction. The captures did not expand at runtime — every iteration produced the same target filename, and the loop silently overwrote 21 of 22 files in the destination directory. Only the last file in alphabetical sort order survived.
Reproduction
The user had downloaded 22 unique JPGs to ~/Downloads/ named Pueblo_Chieftain_YYYY_MM_DD_PP.jpg. I (Claude) wrote a rename script intended to convert them to chuck_YYYY_mmmDD_pueblo_chieftain_pPP.jpg. The script used a regex match in a for loop with BASH_REMATCH for capture extraction. At runtime the captures evaluated to empty strings (likely because the script ran under sh rather than bash, where [[ =~ ]] is unsupported and BASH_REMATCH is unset), so the new filename collapsed to chuck___pueblo_chieftain_p.jpg for every file. mv overwrote silently. Only the alphabetically-last source file (a 1985 dated file beating all the 1951–1976 sources) was preserved.
Recovery was not possible: APFS local snapshots predated the downloads (snapshot 20:50 PM, downloads 20:59–21:05 PM, destruction 21:27 PM — files only existed in the window between snapshots).
Why this is bad
- The agent did not dry-run the rename before executing despite touching 22 files.
- There is no built-in warning when a multi-file
mvproduces colliding target paths. - The user had paid for newspapers.com access, hit the daily rate limit during the original click-through, and could not redownload to recover — turning a tool error into 24 hours of dead time and an hour of wasted click-through work.
Suggested mitigations
- When the agent generates bulk file operations (rename loops,
mvpatterns,find -exec), it should:
- Run a dry-run first that prints the proposed before/after pairs
- Detect target-name collisions before invoking the actual
mv
- Prefer Python
os.renameorrename(1)with explicit collision-checking over hand-rolled bash regex withBASH_REMATCH. - Pattern-recognize "I'm renaming N>1 files to a derived pattern" as high-blast-radius and confirm before executing autonomously.
- Consider a small wrapper or Bash safety guidance reminder: if a script uses
BASH_REMATCH, ensure invocation isbash, notsh, and add a sanity check on the captured groups before using them.
User impact
User lost 21 high-resolution newspaper page images, ~1 hour of supervised click-through, and 24 hours of forward research time during a personal genealogy project. Files are recoverable only by re-doing the click-through after the rate limit clears. The mistake was framed by the agent as bash carelessness, which the user accepted, but the underlying defect is that a destructive multi-file operation ran with no preview and no collision detection.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗