I have around 200 folders, each with 1000 or more jpegs inside, that all need zero padding to 4 digits. Some of these folders have further subdirectories containing deeper images. The photos are all named differently (ie in one folder they may be called Image_1.jpg, Image_11.jpg, etc, while another photo may contain files called Photo01.jpg, Photo02.jpg)

├── folderA
│   ├── subfolder1
│   │   ├── Photo_1.jpg
│   │   └── Photo_11.jpg
│   └── subfolder2
│       ├── image001.jpg
│       ├── image002.jpg
│       └── image003.jpg
└── folderB
    ├── subfolder1
    │   ├── foto_01.jpg
    │   └── foto_01.jpg
    └── subfolder2
        ├── foto_01.jpg
        ├── foto_02.jpg
        └── foto_03.jpg

Can anyone tell me how to run a command that will go into all subfolders and zero pad the numbers in a filename to 4 characters?

2 Answers 2


Use perl rename:

rename -n --filename  's/\d+/sprintf("%04d",$&)/e' *.jpg

or recursive:

find . -type f -name "*.jpg" -exec rename -n --filename 's/\d+/sprintf("%04d",$&)/e' {} +
  • the --filename flag makes sure to rename the filename only, not the path, otherwise you will end up with subfolder0001, etc.
  • Remove the -n if you're happy with the output.

See also

  • perfect! Thank you so much! Jul 19 at 10:13

For a solution that doesn't use the Perl module rename that works for this use case:

files=$(find . -name '*.jpg' -type f)

newfiles=$(echo "$files" \
| sed -E 's|(.*/.*[^[:digit:]]+)([[:digit:]]+)(\.jpg)|\1\t\2\t\3|' \
| awk -F '\t' '{print $1 sprintf("%04d",$2) $3}')

while read f1; read -u 3 f2; do
    echo mv "$f1" "$f2"
done <<< "$files" 3<<< "$newfiles"


The files variable stores all the jpgs found. You can use "-regex" with find if you want.

The newfiles variable stores the new jpg filenames. The code separates out the pathname into three parts, with the middle part being the numbers at the end of the jpg filenames, which are then zero-padded to a width of 4.

The while loop reads in both variables, and executes any command using the lists of filenames found within those two variables. In this case, it is echoing the mv commands to the screen. Remove the echo to perform the actual move.

This code can be improved to work with paths which contain newlines, tabs, or backslashes by adding in null characters between filenames and reading those in with read -d, adding read -r, etc.

You can use and modify this in a future use scenario, for things other than renaming.


Here's the output for your sample directory tree:

mv ./folderB/subfolder2/foto_01.jpg ./folderB/subfolder2/foto_0001.jpg
mv ./folderB/subfolder2/foto_02.jpg ./folderB/subfolder2/foto_0002.jpg
mv ./folderB/subfolder2/foto_03.jpg ./folderB/subfolder2/foto_0003.jpg
mv ./folderB/subfolder1/foto_01.jpg ./folderB/subfolder1/foto_0001.jpg
mv ./folderB/subfolder1/foto_02.jpg ./folderB/subfolder1/foto_0002.jpg
mv ./folderA/subfolder2/image002.jpg ./folderA/subfolder2/image0002.jpg
mv ./folderA/subfolder2/image003.jpg ./folderA/subfolder2/image0003.jpg
mv ./folderA/subfolder2/image001.jpg ./folderA/subfolder2/image0001.jpg
mv ./folderA/subfolder1/Photo_1.jpg ./folderA/subfolder1/Photo_0001.jpg
mv ./folderA/subfolder1/Photo_11.jpg ./folderA/subfolder1/Photo_0011.jpg

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.