When renaming files, is it possible to do character substitution?

Started by jdglanville, November 25, 2010, 09:13:01 PM

Previous topic - Next topic

jdglanville

Hello all,

I've finally figured out the command necessary to rename all the images in a directory to my liking.  It goes something like this:  exiftool -d %Y/%m/%d/%Y%m%d-%H%M%S '-filename<${DateTimeOriginal}-${filenumber}-${model}.%e' .

The problem I'm now dealing with is that ${model} for me contains spaces. (Canon EOS 30D)  Is there a simple way to have all spaces replaced with underscores?


An additional sideline question: in the examples section of the documentation, some of the variables have currly brackets while others do not.  Specifically the line: exiftool '-FileName<${CreateDate}_$filenumber.jpg' -d %Y%m%d *.jpg  Is there a difference?

Phil Harvey

You can create a user-defined "MyModel" tag with the following config file to do what you want:

%Image::ExifTool::UserDefined = (
    'Image::ExifTool::Composite' => {
        MyModel => {
            Require => 'Model',
            # translate spaces to underscores
            ValueConv => '$val =~ tr/ /_/; $val',
        },
    },
);
1;  #end


The curly brackets are only necessary if the character immediately following the tag name is A-Z a-z 0-9 - _ : or # (ie. any character that is valid in a tag name).  Otherwise ExifTool would think the character was part of the tag name.

- Phil

Edit: If you use Safari to cut and paste the example config file you will get errors when you try to use it because some spaces will be copied as non-breaking-space characters.  So use another browser or replace all the characters that look like spaces with ASCII space characters.
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

jdglanville

So, if I take what I've learned here and extend it a little ...

Lets say I want no only spaces to underscores, but also to remove the "Canon " from the model name (let's face it, it's not the model, it's the Make):


%Image::ExifTool::UserDefined = (
    'Image::ExifTool::Composite' => {
        MyModel => {
            Require => 'Model',
            # translate spaces to underscores
            ValueConv => '$val =~ s{Canon }{}; $val =~ tr/ /_/; $val',
        },
    },
);
1;  #end


I'm not 100% of the syntax (it's been a couple of years since I've used Perl), but I think the substitution command gives the general idea.

Phil Harvey

...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

envoy510

I found this page via google and it was very helpful.  In the hopes that my additions to what I found here will be helpful to others, I'm posting my mods here.

The improvements are to handle H.265 files out of my Panasonic TS3.  I had a heck of a time figuring out the fact that the Make was a number and what it meant.

I also want to use a smaller abbreviation for the Model, and I want either 1) the Canon File Number, or a 2) Sequence Number.

First, the command line I use:


exiftool \
    -ext '*' --ext avi \
    -r \
    -d %Y%m%d-%H%M-%S \
    '-filename<${DateTimeOriginal}${MyFileNumber}-${MyModel}.%e' \
    .


The entirety of my .ExifTool_config file:

%Image::ExifTool::UserDefined = (
    'Image::ExifTool::Composite' => {
        MyModel => { # Abbreviate the model number for inclusion into filename
            Desire => {
        0 => 'Model',
# always exists, AFAIK:
        1 => 'Make',
    },
            ValueConv => q{
    my $name;
$name = defined $val[0] ? "$val[0]" : "$val[1]";

# H.264 videos have numeric Make
# Numeric values are from:
                #   https://exiftool.org/TagNames/H264.html
if ($name =~ /^\d+$/) {
    return "Pana-H264"  if $name ==  0x103;
    return "Sony-H264"  if $name ==  0x108;
    return "Canon-H264" if $name == 0x1011;
    return "UNKNOWN-H264-VALUE:$name";
}

        # Phones:
        $name =~ s{Galaxy Nexus}{GN};

    # Canon:  ORDER IS IMPORTANT!
        $name =~ s{Canon EOS 5D Mark III}{5D3};
        $name =~ s{Canon EOS 5D Mark II}{5D2};
        $name =~ s{Canon EOS 7D}{7D};

# Panasonic, remove DMC- prefix, leave rest.
$name =~ s{DMC-}{};

return "$name";
    },
        },

# Would it be better to key on Make?????
        MyFileNumber => {
    Desire => {
    # Canon.  Example: "100-3504".
        0 => 'FileNumber',
# Panasonic.  Usually 0.
1 => 'SequenceNumber',
# dummy value that must exist and is ignored.
2 => 'Make',
    },
    ValueConv => q{
    if (defined $val[0]) {
    # probably Canon, look for "100-" and remove it
    my $fn = $val[0];
    $fn =~ s{^100-}{};
    return "-$fn";
}
return "$val[1]" if defined($val[1]);
return 0;
    },
    PrintConv => 'sprintf("%02s",$val)',
        },
    },
);

1;  #end


This thread really helped me, so I hope it helps others...

Phil Harvey

Well done.  I understand your confusion with the numerical Make.  It isn't well documented that the $val values in the ValueConv are the numerical values (same as with the -n option).  I will see what I can do about improving this in the documentation.

- Phil

Edit: I have changed the description of the first Composite tag in the sample config file to try to make this more clear:

        # Composite tags are unique:  The Require/Desire elements specify
        # tags that must/may exist, and the keys of these hashes are used as
        # indices in the @val array of the ValueConv expression to access
        # the numerical (-n) values of these tags.  All Require'd tags must
        # exist for the Composite tag to be evaluated.  If no Require'd tags
        # are specified, then at least one of the Desire'd tags must exist.
        # See the Composite table in Image::ExifTool::Exif for more examples,
        # and lib/Image/ExifTool/README for all of the details.
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).