Renaming hundreds of files at once for proper sorting
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
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.jpg
after 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.
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])