Batch-rename files on a Mac with a preview first

A zsh rename plan that preserves extensions, ignores directories and symlinks, and refuses existing destinations before moving any files.

A one-line rename loop can overwrite files or start numbering files it has just renamed. For anything valuable, work on a backed-up copy and inspect a complete plan first.

Preview a numbered sequence

Save this outside the target folder as rename-files.zsh. Run zsh rename-files.zsh /absolute/path/to/copied-images. It selects regular, non-hidden files in filename order and preserves the final extension. It does not recurse into directories.

#!/bin/zsh
emulate -LR zsh
setopt ERR_EXIT NO_UNSET PIPE_FAIL

apply=0 # Keep 0 for a preview. Change to 1 only after reviewing it.
(( $# == 1 )) || { print -u2 'Supply one directory.'; exit 1; }
cd -- "$1"

typeset -a sources targets
integer number=0
for item in ./*(.N); do
  [[ -L "$item" ]] && continue
  (( ++number ))
  extension=${item:e}
  suffix=''
  [[ -n "$extension" ]] && suffix=".$extension"
  printf -v destination './image-%03d%s' "$number" "$suffix"
  if [[ -e "$destination" || -L "$destination" ]]; then
    print -u2 "Destination already exists: $destination"
    exit 1
  fi
  sources+=( "$item" )
  targets+=( "$destination" )
done

for (( index=1; index <= ${#sources}; index++ )); do
  printf '%q -> %q\n' "${sources[index]}" "${targets[index]}"
done

if (( apply )); then
  for (( index=1; index <= ${#sources}; index++ )); do
    mv -n "${sources[index]}" "${targets[index]}"
  done
fi

The arrays freeze the source list before any move. All destinations are checked before the second loop starts, and mv -n adds a no-overwrite guard. Spaces, multiple dots and leading hyphens are handled without splitting filenames into arguments.

Keep the rename window quiet

Do not run another importer or renamer against the same folder while this runs. The batch is not a filesystem transaction: interruption can leave it partly renamed, and mv -n can skip a destination created by another process. Keep the printed plan and backup, then compare the resulting filenames before continuing.

This is zsh, not a portable Bash or sh script. It deliberately stops on existing numbered destinations instead of attempting a risky in-place name swap. See zsh glob qualifiers and filename modifiers.

Original version9 November 2014

Kept here for reference and earlier links. The updated guide above is the recommended starting point; older code may depend on retired services or different software versions.

Have you ever had a folder of images with completely random file names and just wished they were all in a clean numeric order, eg: 1.jpg, 2.jpg etc?

This code byte is a simple way of achieving just that.

Fire up your Mac Terminal and follow the following steps:

Open Applications>Utilities>Terminal.app.

And follow the code byte below, basically you CD (Change directory) so terminal is looking at the folder you want to make changes to and then pretty much copy-paste the single line loop. It will rename files into the 00n.fileExtension format. Eg: 001.jpg, 002.jpg, 003.png.


cd ~/yourfolderlocation/path/imagesarehere/
// (Or type cd and then drag the folder onto terminal

i=1; for f in *; do mv "$f" $(printf %03d $i).${f#*.}; let i++; done

Explanation:
for each file found; do "move" filename variable"; done loops over your files. file is the variable that holds filenames.

n, initially set to 1 and increased by one in every iteration with let n++, is the integer suffix for the renamed files.

If you wish to get fancier and control the naming structure it's this line that handles the naming:
$(printf %03d $i).${f#*.}
Where %03d $i is 001 and .${f#*.} is the file extension.

Keep exploring

A couple more useful notes.