Bulk renames are the kind of thing that lives in a Stack Overflow tab forever. The shell has half a dozen ways to do it — mv in a for loop, rename, prename, mmv, plain find -exec — and they all have small, infuriating differences across distros.
1. Add a date prefix
$ clai add today's date prefix to all .jpg files here→ for f in *.jpg; do mv -- "$f" "$(date +%Y-%m-%d)_$f"; done2026-04-27_DSC_0001.jpg2026-04-27_DSC_0002.jpg
The -- "$f" part is doing real work — it stops mv from interpreting filenames that start with a dash as flags. Easy to forget when writing the loop yourself.
2. Swap extensions
$ clai change .jpeg to .jpg for all files in this folder→ for f in *.jpeg; do mv -- "$f" "${f%.jpeg}.jpg"; done
Pure shell parameter expansion, no external tools. Works the same on Linux and macOS — which rename does not.
3. Normalize spaces
$ clai replace spaces with underscores in all filenames here→ for f in *\ *; do mv -- "$f" "${f// /_}"; donemy report.pdf -> my_report.pdfproject notes 2026.txt -> project_notes_2026.txt
The glob *\ * only matches files that contain a space, so the loop doesn't run if there's nothing to do. CliAI tends to add small guards like this.
When clai outpaces a Bash one-liner
For anything more than these patterns — case conversion, regex captures, recursive subtree renames — ask in plain words and let the model assemble the right find -exec rename 's/.../...' '{}' + or mmv invocation. You're going to read the result anyway; the inspect-then-run loop is the safety net.
See also
- Find large files for the select half of the problem.
- From one-liner to script — when a rename pattern earns a checked-in
.sh.