I have a small collection of digital cameras which get used across the family and to help with filing them I want to be able to dump all the photos into a single directory and then use exiftool to rename these (based on camera model_date and time taken) and place them into specific directories (based on the camera model). I have been using shuttercount on some cameras but will likely standardise on the date and time.
One issue I have is, in some cases, I want to modify the ${model} output to something slightly more useful, i.e I have an Olympus mju770sw for which ${model} = u770SW,S770SW (see below for the command I use to rename these files).
So far I have been running multiple exiftool commands to do what I want, e.g. exiftool '-r' '-directory=/Users/kbt_minimac/Desktop/picturestosort/OLYMPUS MU770SW_JPG/' '-d' %Y_%m_%d_%H_%M_%S '-filename<OLYMPUS MJU770SW_${datetimeoriginal}%-c.%e' '/Users/kbt_minimac/Desktop/picturestosort1/' . I then use other similar commands for the other cameras.
However, I would like to run a single file (possibly a batch file) to make my life a bit easier.
When I try the following command it works fine for the Nikon models but also creates directories for the non-Nikon cameras.
exiftool '-Directory</Users/Macbook/Desktop/picture test/Pictures2/${model}_%e' -if '$model = ~ /Nikon/' '-filename<${model}_00${shuttercount}%-c.%e' '/Users/Macbook/Desktop/picture test/Pictures1' '-r'
So,
1. can I stop the above creating all the other directories? Is my '-if' incorrect?
2. can I use a single command that will work on every file and vary the output directory based on ${model} - by using user-defined tags? I have tried to find suitable documentation but not found anything that makes sense to me! I am happy to be pointed to the appropriate documentation and have another try to work it out.
Not sure if this is easy or difficult but hopefully someone can provide guidance.
thanks
First, the problem with the -if expression is that there can't be a space inside the '=~' operator.
About the UserDefined tag, see this thread (https://exiftool.org/forum/index.php/topic,3788.msg17464.html#msg17464) for an example.
The ValueConv expression may be any valid Perl expression as a string, even something iike this:
ValueConv => q{
if ($val =~ /u770SW/i) {
return 'OLYMPUS MU770SW';
} elsif ($val =~ /something else/i) {
return 'SOME OTHER CAMERA';
} else {
return $val;
}
},
- Phil
Thanks very much.
My 'if' was also not working because I hadn't worked out it is case-sensitive (which, if I have interpreted correctly, the /i overrules).
I got the userdefined tag script working once I had figured out that the last comma in your example script wasn't needed!
A couple of other queries...
Out of interest, what does the q do at the start of ValueConv => q{ ?
Lastly, because I have a Nikon D70 and a Nikon D700, I have put D700 before D70 in the script which seems to works correctly, i.e D700 is named as such and D70 is named as such. But can I make the $val =~ command more robust in these cases, i.e. so only if it finds D70 (generally this should be as part of NIKON D70) will it rename files with NIKON D70? I was trying to avoid being so specific as $val = 'NIKON D70' but that might be the simplest solution.
Quote from: fteman on December 20, 2011, 08:51:09 AM
My 'if' was also not working because I hadn't worked out it is case-sensitive (which, if I have interpreted correctly, the /i overrules).
Correct.
QuoteI got the userdefined tag script working once I had figured out that the last comma in your example script wasn't needed!
Not needed, but certainly not a problem. In Perl, an extra comma after the last item in a list or hash isn't a problem. So there must have been something else going on here.
QuoteOut of interest, what does the q do at the start of ValueConv => q{ ?
There are lots of ways to quote a string in Perl. (http://www.perlmonks.org/?node_id=401006) Basically,
q{...} is like
'...' in Perl.
QuoteLastly, because I have a Nikon D70 and a Nikon D700, I have put D700 before D70 in the script which seems to works correctly, i.e D700 is named as such and D70 is named as such. But can I make the $val =~ command more robust in these cases,
Yes, a "\b" matches only at the end of a word. ie)
$val =~ /NIKON D70\b/i will not match "NIKON D700". Google for "Perl regular expressions" if you want to learn more about this.
- Phil
QuoteNot needed, but certainly not a problem. In Perl, an extra comma after the last item in a list or hash isn't a problem. So there must have been something else going on here.
Not being familiar with Perl, I had sort of assumed that the }, closed a { so I had used it more than once. Of course, this wasn't the case earlier in your example script. It took me a while to work this out!
QuoteThere are lots of ways to quote a string in Perl. (http://www.perlmonks.org/?node_id=401006) Basically, q{...} is like '...' in Perl.
Yes, a "\b" matches only at the end of a word. ie) $val =~ /NIKON D70\b/i will not match "NIKON D700". Google for "Perl regular expressions" if you want to learn more about this.
Thanks I will try the \b and take a look at the links and Google search.
I am about to run my script on a (backup) of my library, I am sure this will throw up some minor issues to resolve so I might be back for further advice.
Thanks again for your advice and for Exiftool.
Kevin
OK things are working well but I get a few warnings/errors. I have run the following command to get a list of all files with warnings (I have also done the same with error instead of warning).
exiftool -if '$warning' -r -T -filename -directory -warning DIR > outputfile.txt
As I have multiple copies of my library I want to know if I have a 'good' copy in another library. I could search through the outputfile(s) to see if the warning shows up across all libraries but it would be easier to check if I had the warning/error in the filename?
I have tried to set the warning as a user defined tag but it doesn't work.
MyWarning =>
{
Desire => 'Warning',
ValueConv => q
{
if ($warning)
{
return '$warning';
}
else
{
return 'No Warning';
}
}
},
I have tried just to reference warning in the filename output '-filename<${MyModel} ${datetimeoriginal} ${MyUniqueID} ${warning} %-c.%e' but also without success.
I am not sure if I am missing something obvious or trying to do something not possible. This is the full command I run:
exiftool -config '/Volumes/FreeAgent GoFlex Drive/Photos_Program_Files/renameallconfig' '-directory</Path/Photos_Main_Library/${MyDirectory}/${MyModel} %e' '-filename<${MyModel} ${datetimeoriginal} ${MyUniqueID} ${warning} %-c.%e' '-d' %Y' '%m' '%d' '%H' '%M' '%S '/Path/Photos_To_Rename_And_File' '-r'
Thanks, Kevin
Hi Kevin,
Interesting. There were 2 problems in your MyWarning definition:
1) Use $val instead of $warning
2) Don't quote the returned $val
Here is the fixed version:
MyWarning =>
{
Desire => 'Warning',
ValueConv => q
{
if ($val)
{
return $val;
}
else
{
return 'No Warning';
}
}
},
- Phil
Thanks
However, this isn't doing what I was expecting it to do. For a file with no warnings I was expecting MyWarning to be set as 'No Warning' but I get an Terminal output saying 'Warning: [minor] Tag "MyWarning" tag not defined' and nothing is appended to the filename. Also, when I get 'Warning: [minor] "datetimeoriginal" not defined' this is not appended to the filename.
I have set the MyWarning as a composite tag and used ${MyWarning} in the -filename text.
I only seem to generate minor warnings, is this an issue?
Kevin
Right. I didn't think this through. At least one of the Desire'd/Require'd tags must exist. Try this:
MyWarning =>
{
Desire => {
0 => 'Warning',
1 => 'FileName',
},
ValueConv => q
{
if ($val)
{
return $val;
}
else
{
return 'No Warning';
}
}
},
The minor warnings may be ignored with the -m option. Usually errors in the maker notes are considered minor.
- Phil
Thanks - that also explained an issue I was seeing with another of my user defined tags. I have made an edit to my code to ensure that they always succeed.
A query: does Require require all inputs to have values and Desire require at least one input to have a value?
Kevin
Hi Kevin,
Correct. Here is the full description from lib/Image/ExifTool/README:
Require : [Composite tags only] A hash reference specifying the tags
required to calculate the Composite tag value. The hash
values are the names of the required tags, and the keys
specify the indices where the tag values are stored in the
@val list used in the ValueConv and/or PrintConv expression.
The Composite value is only calculated if the values for all
Require'd tags are defined. Require, Desire and Inhibit tag
names may be prefixed by an optional group family 0 or 1 name
followed by a colon. Case IS significant. The keys used by
the Require, Desire and Inhibit hashes must not overlap (since
they are used as indices into the common @val, @prt and @raw
lists), and together the keys must be sequential starting from
0. A special feature allows a scalar tag name to be used
instead of the hash reference when only the 0th tag is
defined. For example, the following two definitions are
equivalent:
Require => { 0 => 'XMP:Title' },
Require => 'XMP:Title',
Desire : [Composite tags only] This is the same as Require except that
the Composite value is calculated even if the specified tags
don't exist. Beware that the elements of @val, @prt and @raw
may be undefined for Desire'd tags. Even if no tags are
Require'd, at least one of the Desire'd tags must exist for
the Composite tag to be generated.
Inhibit : [Composite tags only] Similar to the Require and Desire
hashes, except that the Composite tag is NOT built if any of
the Inhibit tags exist.
- Phil