I have a ton of files, all named stuff like 1.jpg, 2.jpg, 3.jpg, and so on up to 1439.jpg, however, I have a problem with one of my projects and alphabetizing. It will usually go in the order 1.jpg, 10.jpg, 11.jpg and so on.

What I need is some way to name the files so they are in the format such as 00001.jpg all the way up to 01439.jpg.

How would I be able to do this quickly and efficiently?

  • What you are looking for is "natural sorting", maybe this helps: askubuntu.com/questions/41390/… May 28 '14 at 12:25
  • Answer that isn't a direct answer? ls -v unix.stackexchange.com/questions/33909/…
    – WernerCD
    May 28 '14 at 13:28
  • +1 because I have tried unsuccessfully to do this in pyrenamer.
    – Parto
    May 28 '14 at 14:30
  • @FabianBlechschmidt, I need this in a program which isn't for nautilus or similar. It is for an individual project.
    – Kaz Wolfe
    May 29 '14 at 20:29
  • I think you thought about implementing natural sorting? But I understand, renaming files is quite easy and if it does the job, great :) May 30 '14 at 9:39

Ubuntu comes with a script called rename. It's just a little Perl script that features a number of powerful bulk-renaming features but the best (in this case) is the ability for it to run Perl during the replacement. The result is a truly compact solution:

rename 's/\d+/sprintf("%05d", $&)/e' *.jpg

This is similar to the other printf-style answers here but it's all handled for us. The code above is for a 5-digit number (including a variable number of leading zeros).

It will search and replace the first number-string it finds with a zero-padded version and leave the rest of the filename alone. This means you don't have to worry too much about carrying any extension or prefix over.

Note: this is not completely portable. Many distributions use rename.ul from the util-linux package as their default rename binary. This is a significantly stunted alternative (see man rename.ul) which won't understand the above. If you'd like this on a platform that isn't using Perl's rename, find out how to install that first.

And here's a test harness:

$ touch {1..19}.jpg

$ ls
10.jpg  12.jpg  14.jpg  16.jpg  18.jpg  1.jpg  3.jpg  5.jpg  7.jpg  9.jpg
11.jpg  13.jpg  15.jpg  17.jpg  19.jpg  2.jpg  4.jpg  6.jpg  8.jpg

$ rename 's/\d+/sprintf("%05d", $&)/e' *.jpg

$ ls
00001.jpg  00005.jpg  00009.jpg  00013.jpg  00017.jpg
00002.jpg  00006.jpg  00010.jpg  00014.jpg  00018.jpg
00003.jpg  00007.jpg  00011.jpg  00015.jpg  00019.jpg
00004.jpg  00008.jpg  00012.jpg  00016.jpg

And an example prefixes (we aren't doing anything different):

$ touch track_{9..11}.mp3 && ls
track_10.mp3  track_11.mp3  track_9.mp3

$ rename 's/\d+/sprintf("%02d", $&)/e' *.mp3 && ls
track_09.mp3  track_10.mp3  track_11.mp3
  • If I were a Perl person this would be the perfect solution. Really neat.
    – MGP
    May 28 '14 at 12:55
  • 2
    It doesn't use any perl, just a tool supplied that's already written in perl.
    – Rob
    May 28 '14 at 16:22
  • 1
    In this case it does involve a single Perl command but it's not exactly heavy lifting. sprintf in Perl behaves similar to sprintf in other languages.
    – Oli
    Mar 7 '16 at 11:47
  • What does $& mean?
    – user2740
    Apr 17 '20 at 12:06
  • @user2740 it's a placeholder variable for the current filename
    – Oli
    Apr 17 '20 at 13:47
for f in *.jpg ; do if [[ $f =~ [0-9]+\. ]] ; then  mv $f `printf "%.5d" "${f%.*}"`.jpg  ; fi ; done



  • if [[ $f =~ [0-9]+\. ]] makes sure that only files whose names are numbers (followed by a dot) are being renamed.
  • printf "%.5d" NUMBER adds the leading zeroes
  • "${f%.*}" cuts the extension (.jpg) and leaves just the number
  • .jpgafter the second backtick adds the file extension again.

Note that this will work only on file names that are numbers. Left-padding leading zeroes to non-numbered files would require different format.

If you want to experiment try this command:

for f in *.jpg ; do if [[ $f =~ [0-9]+\. ]] ; then echo mv $f `printf "%.5d" "${f%.*}"`.jpg  ; fi ; done

Edit 2

Made the command safer by making sure that only file names that are numbers are being renamed. Note that any pre-existing files named like 00001.jpg will be overwritten.

  • This one liner script works 'out of box' on Ubuntu and other Linux distros! 😃 No need to install any additional tools using perl, python, etc. Mar 17 '19 at 20:53
  • Works also on FreeBSD; one caveat: files like 5.1.cbz get treated like 5.cbz and lead to overwriting them. Get them out of the way first.
    – emk2203
    Apr 13 '21 at 8:15

Below a python script.

The script adds leading zeros up to the defined number of digits. If the name is larger than that, the file(name) is untouched.

Combining different extensions in one rename action might add some convenience. To add extension(s), simply add them to the tuple, for example extensions = (".jpg", ".jpeg", ".tiff").

Copy the text into an empty file, save it as rename.py, enter the correct path to the files directory (sourcedir), the number of digits you'd like the new names to have (number_ofdigits) and the file extension(s) to rename (extensions)

Run it by the command:

python3 /path/to/script/rename.py

The script:


import shutil
import os

sourcedir = "/path/to/files"; number_ofdigits = 5; extensions = (".jpg", ".jpeg")

files = os.listdir(sourcedir)
for item in files:
    if item.endswith(extensions):
        name = item.split("."); zeros = number_ofdigits-len(name[0])
        newname = str(zeros*"0")+name[0]+"."+name[1]
        shutil.move(sourcedir+"/"+item, sourcedir+"/"+newname)


Below a slightly improved version. It automatically determines the longest name in the directory, and adds leading zeros up to the length of the longest name.





No need to set the number of digits.


import shutil
import os

sourcedir = "/path/to/files"; extensions = (".jpg", ".jpeg")
files = [(f, f[f.rfind("."):], f[:f.rfind(".")]) for f in os.listdir(sourcedir)if f.endswith(extensions)]
maxlen = len(max([f[2] for f in files], key = len))

for item in files:
    zeros = maxlen-len(item[2])
    shutil.move(sourcedir+"/"+item[0], sourcedir+"/"+str(zeros*"0")+item[0])

There is a rename utility implemented in Perl that makes this very easy:

rename 's/\d+/sprintf("%05d",$&)/e' *.jpg

The first argument is a Perl expression that is evaluated for each file name.

  • I some machies the "rename" not ponts to the proper perl-rename, so: we have to open the perl package manager cpan and run cpan1> install File::Rename Nov 15 '20 at 13:04
  • Indeed, and on Ubuntu 20.04 it can be installed using sudo apt install rename Nov 16 '20 at 7:28

There is a GUI that will do this called pyRenamer which can be found in the repositories. Install, start, select your directory and just set the 'Renamed file name pattern' to '{num5}'on the 'Patterns' tab and click the 'Rename' button. You can also preview what will happen prior to renaming.

  • While your answer DOES work, please note that this is a shell-scripting section, meaning I am looking for a commandline answer. Also, can you provide more detail about the program? For instance, what pattern format is {num5}?
    – Kaz Wolfe
    Jun 29 '14 at 5:04

If by any chance your rename command is not perl-rename, you can use this perl code:

foreach (<*.jpg>) { rename $_, sprintf("%03d.jpg", $1) if /^(\d+).jpg/; }

When we say foreach we can refer to the files by $_

But you can install the propper perl-rename with this commands

cpan1> install File::Rename

Another way of renaming these files easily is opening the folder with ranger file manager, select all files, run :bulkrename and use this vim command:

:%s/^\d\+/\=printf("%03d", submatch(0))

I have also tried using ls + awk

ls -1 | awk -F. '{printf "%s%s%s%03d.%s\n", "mv ", $0, " ", $1, $2}'

Each string or number must be associated on the printf function, the result output will be something like this:

mv 9.jpg 009.jpg

To really perform the renaming with this you have to add | sh at the end of it:

ls -1 | awk -F. '{printf "%s%s%s%03d.%s\n", "mv ", $0, " ", $1, $2}' | sh
for file in `(find * -maxdepth 1 -type f -name "*.jpg")`     
  mv $file "000"$file    

This is crude, since it doesn't do the renaming intelligently, will need to think of a trick for that. But it should help you sort stuff.

Update: Well you have a more complete answer.

  • 2
    it renames 1439.jpg as 0001439.jpg. May 28 '14 at 5:28
  • Yes, I know, just padded extra zeroes which should still work with the sort. May 28 '14 at 12:30

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.