Batch rename -- multiple image types
Andrew Mclaughlin
I have a large number of images that I copied from a failing external hard drive. All of the images are fine and have no corruption, but oddly a large number of them are now missing extensions. The files are a mix of jpg, png, and gif, and are named in the following structure, all in a single folder.
1
2
3
4.jpg
5.png
etcSome files have extensions, while many do not and are just the numbers. There are roughly 4000 images in this folder, so manually renaming is not an option.
Is there any script or program that can be used to determine the extension via meta-data and add it to the files as needed?
I have used "pyrenamer" from the software center for years for renaming files, but it doesn't appear to be able to add extensions.
Any help would be greatly appreciated, my coding sucks and I can't figure it out on my own.
13 Answers
Below a python solution (script).
The script uses the imghdr module to recognize the file type. It will add the correct file extensions (if missing), of the following types:
rgb, gif, pbm, pgm, ppm, tiff, rast, xbm, jpeg, bmp, png If the file already has a file extension, it will be skipped. In case the file is of an unknown file type (if it is damaged for example), the file is reported as "could not determine":
could not determine: /home/jacob/Bureaublad/picturetest/blubThe script:
#!/usr/bin/env python3
import os
import imghdr
import shutil
directory = "/path/to/pictures"
for name in os.listdir(directory): # combining file+its directory: file = directory+"/"+name # only files without a dot are subject to renaming (else the file already has a file extension or is a hidden file): if name.count(".") == 0: # fetch the file extension from the file: ftype = imghdr.what(file) # if it is impossible to get the extension (if the file is damaged for example), the file(s) will be listed in the terminal window: if ftype != None: shutil.move(file, file+"."+ftype) else: print("could not determine: "+file)Paste it into an empty file, save it as rename.py, set the directory to the pictures in the directory = "/path/to/pictures" -line and run it by the command:
python3 /path/to/rename.pyRename recursively
In case your images are not in a "flat" directory, but in a layered directory, use the version below. It will check (and repair if necessary) file extensions inside the file's current folder.
#!/usr/bin/env python3
import os
import imghdr
import shutil
directory = "/path/to/pictures"
for root, dirs, files in os.walk(directory): for name in files: file = root+"/"+name if name.count(".") == 0: ftype = imghdr.what(file) if ftype != None: shutil.move(file, file+"."+ftype) else: print("could not determine: "+file) 4 A one-liner using the rename command:
rename 's/.*/use File::MimeInfo::Magic qw#mimetype extensions#; sprintf("%s.%s", $&, extensions(mimetype($&)))/e' * -vnit's using the Perl File::MimeInfo module to query the file (sort of how the file command does) to work out what the file is and then to append the first extension MimeInfo has for that MIME type back onto the file.
In some cases this can result in less commonly used extensions being used (like jpeg or jpe for what most people would name jpg files) but you can do a second pass to correct these quite easily:
rename 's/\.jpe$/.jpg/' *But most applications won't mind if you specify .jpe files so this isn't necessary most of the time.
Both rename commands above are set in test mode.
They won't do anything until you remove the -n argument from the end.
Simple script
#!/bin/bash
for file in ~/path/to/images/*; do TYPE=$(file --mime-type -b "$file" | cut -f2 -d/); if [[ ! $file =~ \.$TYPE ]]; then echo mv -v "$file" "$file.$TYPE"; fi
doneExplanation of TYPE=$(file --mime-type -b "$file" | cut -f2 -d/); (finding file type)
find the extension of each $file using file(determine file type) command.
--mime-type, --mime-encoding option used for print only the specified element(s).
-b, --brief option used for do not prepend filenames to output lines (brief mode).
See also man file for more info.
Now we extracted the file type and saved it into TYPE variable.
And what is cut -f2 -d/ command? This used for printing just extension type, Like png in image/png output from file --mime-type -b "$file" result.
-f2 prints second part with / delimiter(-d option) between fields. ex: Print png in image/png.
See also man cut for more info.
Explanation of if [[...]]; (checking file extension)
We skipped all existing extension with a simple regex, using the =~ operator inside a [[...]] test in if condition:
if [[ $file =~ \.$TYPE ]];While $file is your images filenames and $TYPE is its extension which we found and stored that into TYPE variable in TYPE=$(file --mime-type -b "$file" | cut -f2 -d/);.
Then we skip to rename all files that has an extension with themselves.
! refer to: if file has NO extension with itself, then rename that and add its extension at the end of its name.
Explanation of echo mv -v "$file" "$file.$TYPE";(rename step)
In this line Actually we are appending the file extension(if $file doesn't an extension with itself) at the end of $file file by using mv command. mv also using for renaming Files/Directory.
Then we rename $file to $file.$TYPE. For example file 1 will be rename to 1.png if its file type was png format.
in theory actually above mv command do this: rename filename -> filename.filetypeThat filename stored into $file variable and filetype stored into $TYPE variable.
How can you use this script?
Copy and paste the script in gedit and save it with your favorite name ex: batchRename, then open Terminal and run it by the following command:
bash batchRenameDON'T forget before running script verify your correct images path /path/to/images/ and for renaming on your files after checking the result with echo command, remove echo from the beginning echo mv -v "$file" "$file.$TYPE" and run the script again and enjoy renaming ;)