Bash rename loop silently overwrote 21 user files via failed BASH_REMATCH expansion

Resolved 💬 3 comments Opened Apr 25, 2026 by brandbuilt-hub Closed Apr 28, 2026

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

  1. The agent did not dry-run the rename before executing despite touching 22 files.
  2. There is no built-in warning when a multi-file mv produces colliding target paths.
  3. 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

  1. When the agent generates bulk file operations (rename loops, mv patterns, 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
  1. Prefer Python os.rename or rename(1) with explicit collision-checking over hand-rolled bash regex with BASH_REMATCH.
  2. Pattern-recognize "I'm renaming N>1 files to a derived pattern" as high-blast-radius and confirm before executing autonomously.
  3. Consider a small wrapper or Bash safety guidance reminder: if a script uses BASH_REMATCH, ensure invocation is bash, not sh, 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.

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗