I've got a folder /User/me/Desktop/folder/images with files like key 1--name.jpg, key 10--name1.jpg, etc. The files are sorted incorrectly when fed to my site so I get an arrangement like key 84--name.jpg -> key 9--name.jpg -> key 94--name.jpg instead of key 9--name.jpg -> key 84--name.jpg -> key 94--name.jpg because of character precedence. So I wan to replace all the non-three-digit-length image names like 9, 12, 99 with their three-digit, 0-padded equivalents to get 009, 012, 099 so the ordering will be correct. How can this be done for folder full of files in one line in my Mac terminal.

  • Please see the accepted answer on THIS POST. You need to do some homework, like parsing the file name and extracting the sequence number and reforming the filename but you can figure out the logic.
    – MelBurslan
    Mar 22, 2016 at 20:41

3 Answers 3


Extraxt the number, something like:

$ echo 'key 88--name.jpg' | sed 's/key \([0-9]\+\)--.*/\1/'

Format it with printf:

$ printf '%04d' "88"

reinsert that into the name:

$ echo 'key 88--name.jpg' | sed 's/\(key [0-9]\+--\)/key 0088--/'
key 0088--name.jpg

All in one script:

for f in 'key '*'--name.jpg'; do
    a="$( echo "$f" | sed 's/key \([0-9]\+\)--.*/\1/' )"
    b="$( printf '%04d' "$a" )"
    c="$( echo "$f" | sed 's/\(key '"$a"'--\)/key '"$b"'--/' )"
    echo \
    mv -i "$f" "$c"

Or even faster:

for f in 'key '*'--name.jpg'; do
    a="${f#key }"
    b="$( printf 'key %04d--name.jpg' "$a" )"
    echo \
    mv -i "$f" "$b"

Both scripts will not change anything. They will just list what is going to be changed. If you are happy with what you see, just comment out (add a # in front of) the line echo \. In any case, the mv command will not overwrite any file if the file already exists (the -i option).


If you know in advance how many digits to pad to, this can be done fairly simply by combining the shell's string manipulation and arithmetic features. To pad to 3 digits, number from 1000 and strip away the leading 1.

for current_name in *[0-9]*; do
  # Split the name into prefix, digits, suffix
  prefix=${current_name%%[0-9]*}; suffix=${current_name#"$prefix"}
  # Pad the digits
  digits=${suffix%%[!0-9]*}; suffix=${suffix#"$digits"}
  digits=$((digits+1000)); digits=${digits#1}
  # Rename the file
  if [ "$new_name" != "$current_name" ]; then
    mv -- "$current_name" "$new_name"

The following function computes the number of necessary digits (1 for up to 9 files, 2 for up to 99 files, a.s.o.) and renames the files with the first number in the filename padded with zeros accordingly:

  [[ -d "$folder" ]] || { echo 'need directory argument' && return; }
  [[ -z "$extension" ]] && extension=wav
  if [[ -z "$digits" ]]; then
    amount=$(ls "$folder"/*.$extension | wc -l)
    digits=$(echo "l($amount)/l(10)+1" | bc -l)
  fmt=$(printf '%%0%dd' $digits)
  for f in "$folder"/*.$extension; do
    bn=$(basename "$f")
    number=$(echo $bn | sed -re 's/^[^[:digit:]]*0*([[:digit:]][[:digit:]]*)[^[:digit:]].*/\1/')
    [[ "$bn" == "$number" ]] && continue
    pf_pat=$(echo $bn | sed -re "s/0*$number/$fmt/")
    new_path=$(printf "$folder/$pf_pat" $number)
    [[ "$f" != "$new_path" ]] &&  mv -i "$f" "$new_path"

For .jpg-files call with a second argument jpg. This makes of course only sense if filenames have consecutive numbers in them. Alternatively the number of desired digits can be passed as third argument.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.