2

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

etc

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

  • How exactly did you copied them? – Braiam Oct 20 '14 at 11:26
4

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/blub

The 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.py

Rename 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)
  • works but it replaces the file which has it's extension available already. That is foo.png becomes foo.png.png – Avinash Raj Oct 20 '14 at 12:51
  • @AvinashRaj I corrected a small mistake, but it should not have any effect on what you mention, everything below if name.count(".") == 0: only happens if there is no dot in the name (either invisible or with extension) so it seems impossible that anything happens when there is a file extension already. That is in line with what I tested. – Jacob Vlijm Oct 20 '14 at 12:57
  • +1, could you explain each code by commenting.. – Avinash Raj Oct 20 '14 at 13:00
  • This does works (just tested). Earlier however, I cheated by shorting all files in Nautilus by MIME type, and oddly enough all affected images missing the extension were .jpg. Drive crash effected the files copied off in a strange way. I cut those images to another folder and used Pyrenamer to add the .jpg extension, then moved them back. – KhaosDvorak Oct 21 '14 at 1:57
2

A one-liner using the rename command:

rename 's/.*/use File::MimeInfo::Magic qw#mimetype extensions#; sprintf("%s.%s", $&, extensions(mimetype($&)))/e' * -vn

it'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.

  • e (modifier) at the last helps to execute the code which are present in the replacement part. – Avinash Raj Oct 20 '14 at 11:40
  • Yup, normally a s/a/b/ would literally replace a with b but here, it evaluates the replacement side allow you to do fancy things like this. – Oli Oct 20 '14 at 11:42
  • but it replaces the file which has it's extension available already. That is foo.png becomes foo.png.png – Avinash Raj Oct 20 '14 at 12:50
2

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
done

Explanation 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.filetype

That 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 batchRename

DON'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 ;)

  • Hi KasiyA, take care; it "corrects" my .jpeg into .jpeg.JPEG. why not skip all existing extensions? – Jacob Vlijm Oct 20 '14 at 16:17
  • @JacobVlijm I have updated including skip all existing extension and explanation for each line. Thank you – αғsнιη Oct 21 '14 at 13:07
  • 1
    BTW, I wasn't the person who downvoted. – Jacob Vlijm Oct 21 '14 at 13:14
  • I tried it, it works fine on .jpeg, but my naamloos.bmp is renamed naamloos.bmp.x-ms-bmp – Jacob Vlijm Oct 21 '14 at 13:25
  • 1
    Ah, I see, he indeed only mentioned jpg, gif and png. – Jacob Vlijm Oct 21 '14 at 13:32

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.