27

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?

6
  • What you are looking for is "natural sorting", maybe this helps: askubuntu.com/questions/41390/… May 28, 2014 at 12:25
  • Answer that isn't a direct answer? ls -v unix.stackexchange.com/questions/33909/…
    – WernerCD
    May 28, 2014 at 13:28
  • +1 because I have tried unsuccessfully to do this in pyrenamer.
    – Parto
    May 28, 2014 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, 2014 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, 2014 at 9:39

9 Answers 9

37

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
6
  • If I were a Perl person this would be the perfect solution. Really neat.
    – MGP
    May 28, 2014 at 12:55
  • 2
    It doesn't use any perl, just a tool supplied that's already written in perl.
    – Rob
    May 28, 2014 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, 2016 at 11:47
  • What does $& mean?
    – user2740
    Apr 17, 2020 at 12:06
  • @user2740 it's a placeholder variable for the current filename
    – Oli
    Apr 17, 2020 at 13:47
22
for f in *.jpg ; do if [[ $f =~ [0-9]+\. ]] ; then  mv $f `printf "%.5d" "${f%.*}"`.jpg  ; fi ; done

Edit

Explanation:

  • 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.

2
  • 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, 2019 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, 2021 at 8:15
9

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:

#!/usr/bin/python3

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)

edit:

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.

example:

1.jpg
12.jpg
123.jpg

becomes:

001.jpg
012.jpg
123.jpg

No need to set the number of digits.

#!/usr/bin/python3

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])
2

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.

2
  • 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, 2020 at 13:04
  • Indeed, and on Ubuntu 20.04 it can be installed using sudo apt install rename Nov 16, 2020 at 7:28
0

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.

1
  • 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, 2014 at 5:04
0

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

cpan
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
0

The zsh shell has a loadable zmv module, similar to the external mmv command, and it also supports numeric ranges <m-n> in its shell globs. So for instance given:

 % ls *.mp4
'3 - Ariane Rocket Disaster.mp4'           '81 - Proof of Guarantee (Sketch).mp4'
'39 - Conditions Example.mp4'              '82 - Measured vs. Worst-Case Probability.mp4'
'396 - Execution Path of a Program.mp4'    '86 - Coverage of Random Testing.mp4'
'397 - Computation Tree Example.mp4'       '88 - Intro to Automated Test Generation.mp4'
'398 - Existing Approach I.mp4'            '89 - Outline.mp4'
'399 - Existing Approach II.mp4'           '9 - Program Invariants.mp4'
'400 -  Combined Approach.mp4'             '90 - Korat.mp4'
'401 - An Illustrative Example .mp4'       '91 - The Problem.mp4'
'402 - Computation Tree.mp4'               '92 - An Insight.mp4'
'403 - Computation Tree Solution.mp4'      '94 - Scheme for Representing Shapes.mp4'
'7 - Dynamic Program Analysis.mp4'         '95 - Representing Shapes.mp4'
'78 - Concurrency Bug Depth Solution.mp4'  '96 - Representing Shapes Solution.mp4'
'79 - Cuzz Algorithm.mp4'                  '97 - A Simple Algorithm.mp4'
'8 - Static Program Analysis.mp4'          '98 - Enumerating Shapes.mp4'
'80 - Probabilistic Guarantee.mp4'         '99 - Enumerating Shapes Solution.mp4'

then once the module is loaded as

 % autoload -Uz zmv

you can do

 % zmv -n '(<1-99>) - (*.mp4)' '${(l:3::0:)1} - ${2}'
mv -- '3 - Ariane Rocket Disaster.mp4' '003 - Ariane Rocket Disaster.mp4'
mv -- '39 - Conditions Example.mp4' '039 - Conditions Example.mp4'
mv -- '7 - Dynamic Program Analysis.mp4' '007 - Dynamic Program Analysis.mp4'
mv -- '78 - Concurrency Bug Depth Solution.mp4' '078 - Concurrency Bug Depth Solution.mp4'
mv -- '79 - Cuzz Algorithm.mp4' '079 - Cuzz Algorithm.mp4'
mv -- '8 - Static Program Analysis.mp4' '008 - Static Program Analysis.mp4'
mv -- '80 - Probabilistic Guarantee.mp4' '080 - Probabilistic Guarantee.mp4'
mv -- '81 - Proof of Guarantee (Sketch).mp4' '081 - Proof of Guarantee (Sketch).mp4'
mv -- '82 - Measured vs. Worst-Case Probability.mp4' '082 - Measured vs. Worst-Case Probability.mp4'
mv -- '86 - Coverage of Random Testing.mp4' '086 - Coverage of Random Testing.mp4'
mv -- '88 - Intro to Automated Test Generation.mp4' '088 - Intro to Automated Test Generation.mp4'
mv -- '89 - Outline.mp4' '089 - Outline.mp4'
mv -- '9 - Program Invariants.mp4' '009 - Program Invariants.mp4'
mv -- '90 - Korat.mp4' '090 - Korat.mp4'
mv -- '91 - The Problem.mp4' '091 - The Problem.mp4'
mv -- '92 - An Insight.mp4' '092 - An Insight.mp4'
mv -- '94 - Scheme for Representing Shapes.mp4' '094 - Scheme for Representing Shapes.mp4'
mv -- '95 - Representing Shapes.mp4' '095 - Representing Shapes.mp4'
mv -- '96 - Representing Shapes Solution.mp4' '096 - Representing Shapes Solution.mp4'
mv -- '97 - A Simple Algorithm.mp4' '097 - A Simple Algorithm.mp4'
mv -- '98 - Enumerating Shapes.mp4' '098 - Enumerating Shapes.mp4'
mv -- '99 - Enumerating Shapes Solution.mp4' '099 - Enumerating Shapes Solution.mp4'

where (l:3::0:) in the replacement variable expansion is a modifier that left pads to width 3 using string 0.

Remove the -n flag once you are happy with the proposed renamings.

0

I just found that simply putting all the numbered files without extensions in a folder - then using the Ubuntu FILES GUI "select all" - then you can actually right click and "rename" them all - just put in ".jpg" after the [original filename] box - pretty simply. I was impressed.

-4
for file in `(find * -maxdepth 1 -type f -name "*.jpg")`     
do    
  mv $file "000"$file    
done

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
  • 2
    it renames 1439.jpg as 0001439.jpg. May 28, 2014 at 5:28
  • Yes, I know, just padded extra zeroes which should still work with the sort. May 28, 2014 at 12:30

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .