I have written a bash script that will iterate incoming arguments, build a set of keywords to update and execute ExifTool to update an image.
I am having problems with ExifTool interpreting the arguments passed to it.
I have extracted the gist of what I am doing into a simplified bash script.
Executing ExifTool from within the script fails, it seems to interpret the argument differently.
Echoing to sh seems to work.
Copying the echo output and pasting into terminal also works.
If the Subject has no spaces it works fine.
I am getting errors:
Error: File not found - Village"
Error: File not found - Arnold"
I'm baffled, is this some shell esoterica or a problem with the ExifTool wrapper script.
setsubjects
=======
#!/usr/bin/env bash
filename=test123.jpg
allsubj="-xmp-dc:Subject+=\"Places|Europe|Germany|Small Village\" -xmp-dc:Subject+=\"People|Meyer|Georg Arnold\""
# This works
echo exiftool -overwrite_original ${allsubj} ${filename} | sh
# This does not work
exiftool -overwrite_original ${allsubj} ${filename}
# echo shows the right thing, copy output, paste into terminal works
echo exiftool -overwrite_original ${allsubj} ${filename}
Wow. Tricky.
I haven't figured out the answer yet, but it is clear that the echo command suffers the same problem. It appears the echo works, but it does not. Change the space into more spaces to see what I mean:
allsubj="-xmp-dc:Subject+='Places|Europe|Germany|Small Village'"
echo exiftool -overwrite_original ${allsubj} ${filename}
produces this:
exiftool -overwrite_original -xmp-dc:Subject+='Places|Europe|Germany|Small Village' a.jpg
I don't have time to think about this more now, but I will when I get a chance.
- Phil
I ran the script with bash -x and saw the differences in the echo statements below
#!/usr/bin/env bash -x
filename='test123.jpg'
allsubj="-xmp-dc:Subject+=\"Places|Europe|Germany|Small Village\" -xmp-dc:Subject+=\"People|Meyer|Georg Arnold\""
echo "${allsubj}"
echo ${allsubj}
The echo with the quotes executes as: note has the 2 spaces preserved:
+ echo '-xmp-dc:Subject+="Places|Europe|Germany|Small Village" -xmp-dc:Subject+="People|Meyer|Georg Arnold"'
without quotes, bash interprets the var as:
+ echo '-xmp-dc:Subject+="Places|Europe|Germany|Small' 'Village"' '-xmp-dc:Subject+="People|Meyer|Georg' 'Arnold"'
Strange, I'll add quotes around my variable.
Thanks,
Hmmm, still not right. I noticed that in the first one the string is passed in as one parameter, resulting in setting the xmp subject to include the command.
+ exiftool -overwrite_original '-xmp-dc:Subject+="Places|Europe|Germany|Small Village" -xmp-dc:Subject+="People|Meyer|Georg Arnold"' test123.jpg
Resulting subject:
exiftool -G -s -subject test123.jpg
[XMP] Subject : "Places|Europe|Germany|Small Village" -xmp-dc:Subject+="People|Meyer|Georg Arnold"
OK, here is the solution:
#!/bin/sh
filename='test123.jpg'
allsubj="-xmp-dc:Subject+=Places|Europe|Germany|Small Village"
exiftool -overwrite_original "${allsubj}" "${filename}"
I've used /bin/sh here, but bash should work too (/bin/sh is smaller and lighter though, so the preferred shell for scripts).
The problem is that the shell strips one level of quotes when assigning "allsubj", but apparently doesn't strip quotes from within a shell variable after interpolating the value within a command line... which makes sense now that I think about it. So you must add quotes around the variables in the command instead.
- Phil
Phil, that still doesn't work with
allsubj="-xmp-dc:Subject+=Places|Europe|Germany|Small Village -xmp-dc:Subject+=People|Meyer|Georg"
You get
Subject: Places|Europe|Germany|Small Village -xmp-dc:Subject+=People|Meyer|Georg
I rewrote the script to use an array instead of concatenated strings, seems to work better.
#!/usr/bin/env sh -x
filename='test123.jpg'
# collect subjects as an array
allsubj[0]="-xmp-dc:Subject+=\"Places|Europe|Germany|Small Village\""
allsubj[1]="-xmp-dc:Subject+=\"People|Meyer|Georg Arnold\""
# clear subject
exiftool -q -overwrite_original -xmp-dc:Subject= ${filename}
# This works with array
exiftool -q -overwrite_original "${allsubj[@]}" ${filename}
# Check if it worked
exiftool -G -s -xmp:subject ${filename}
The shell debug output shows that the array expands to one argument per array element, and retains the extra spaces in the subject values:
+ filename=test123.jpg
+ allsubj[0]='-xmp-dc:Subject+="Places|Europe|Germany|Small Village"'
+ allsubj[1]='-xmp-dc:Subject+="People|Meyer|Georg Arnold"'
+ exiftool -q -overwrite_original -xmp-dc:Subject= test123.jpg
+ exiftool -q -overwrite_original '-xmp-dc:Subject+="Places|Europe|Germany|Small Village"' '-xmp-dc:Subject+="People|Meyer|Georg Arnold"' test123.jpg
+ exiftool -G -s -xmp:subject test123.jpg
and the subject written into the xmp shows as 2 elements instead of the previous one concatenated string:
[XMP] Subject : "Places|Europe|Germany|Small Village", "People|Meyer|Georg Arnold"
FYI, in my actual script I have this as a function:
#!/usr/bin/env sh
function setSubject {
filename=$1
shift
declare -a allsubj
index=0
while [ $# -ne 0 ]; do
allsubj[index]="-xmp-dc:Subject+=\"$1\""
((index++))
shift
done
if [ ${#allsubj[@]} -ne 0 ]; then
exiftool -q -overwrite_original "${allsubj[@]}" ${filename}
fi
}
# test it
setSubject test123.jpg "Places|Europe|Germany|Small Village" "People|Meyer|Georg Arnold"
exiftool -G -S -Subject -HierarchicalSubject test123.jpg
Thanks all,
Right. Definitely trickier to have 2 command-line arguments in the same shell variable.
I've never used an interpolated array like this in shell scripting, so you've taught me something. Smart.
- Phil
After some more ExitTool doc reading I could also have collected the just the keywords in a delimited string, with a few extra quotes and escaped quotes:
#!/usr/bin/env sh -x
filename='test123.jpg'
# collect subjects
subj1="Places|Europe|Germany|Small Village"
subj2="People|Meyer|Georg Arnold"
allsubj="${subj1}//${subj2}"
exiftool -q -overwrite_original -sep "//" -xmp-dc:Subject=\""${allsubj}"\" ${filename}
Enough fun, back to work. :)
Hallo to all.
I know is necroposting, but I have the some trouble.
The script returns file not found, but if I execute the command as reported in error copying and pasting in the terminal line it works.
Is the problem still here?
echo "exiftool -p -Keywords=\"${keyword}\" -Title+=\"ERA: ${fname}\" $fname -overwrite_original" | bash
could be a good solution?
And to do this any idea or better solution?
(I try to set the date, if it works (=no Datetimeoriginal was set)go on, otherwise maybe I want to overwrite it.
"exiftool -wm cg -DateTimeOriginal=\"${anno}':01:01 00:00:00'\" -overwrite_original ${fname}"
if [ $? -ne 0 ] #non avevo già una data e l'ho messa
then
datafile=(echo "exiftool -s3 -createdate \"$fname\"") | bash
while true
do
if [ "$anno" -lt 2021 ] #la scrittura della data in EXIF la faccio solo se è un anno minore di 2021. Se ho messo 5060 per indicare anni 50-60 non lo metto
then
read -e -p "Sovrascrivere la data $datafile con $anno?[Yes/No/Vuoto]" -i "Y" yn </dev/tty
else
read -e -p "Sovrascrivere la data $datafile con $anno?[Yes/No/Vuoto]" -i "N" yn </dev/tty
fi
case $yn in
[Yy]* ) echo "exiftool -p -DateTimeOriginal=\"${anno}':01:01 00:00:00'\" -overwrite_original \"${fname}\"" | bash;break;;
[Nn]* ) break;; #Non fo una sega
[0123456789][0123456789][0123456789][0123456789]* ) $("exiftool -p -DateTimeOriginal=\"${yn}:01:01 00:00:00\" -overwrite_original \"${fname}\"");break;;
* ) echo "Inserire Y[es]/N[o] o l'anno";;
esac
done
fi
The problem is also with 12.16
Thanks.