(BASH) Works on the command line, hangs as a script -- what's wrong?
I'm writing a Bash script to take IPTC keywords from a text file and write them, via Exiv2, to several (first batch is 100) JPEG files in a single directory. The script has one while loop inside another while loop, both terminated, but I'm pretty sure that's not my problem. I think it's how I'm incrementing the "counter" variable, although it could also be the method of parsing the text lines from the file (using cut with delimiters that have worked fine in simpler scripts).
Here's the code as I've worked it up to this point. Code:
#!/bin/bash Feeding each line consecutively into a terminal (excepting the exiv2 command) works fine: each variable echoes with the part of the text line used as a variable value as it should, even when the b variable is incremented the quick&dirty way (up arrow three commands and hit enter). Running the above script in eval mode (sh -x) stalls after setting the b variable to one and reading in the first line of text. I'd like to know why. I'd also like some advice on another reliable method of parsing the read-in lines. Thanks in advance. BZT |
Can we see an example of the input files, so we know what it's working with? Also, exactly what output do you get?
There are multiple problems with this script, as well as some other things that I want to comment on. 1. $(..) is recommended over `..` 2. Code:
while read 'line'; 3. Code:
n=`echo $line` 4. Code:
b=$(( $b + 1 )) Edit: 5. Code:
commaz=`echo -e $taxt | grep -o "," | wc -l | sed s/\ //g` Edit2: 6. Code:
while [[ $b -le $commaz ]]; do Edit 3 7. Code:
b=1 |
1.Regarding item 1 in your reply:
For what it's worth, all the ticks in the script have now been changed to dollar sign-parentheses pairs. Moving on... 2.Regarding item 5, ditto: This came from an earlier script that was written to count the commas in the line read by "while read" from the text file. It occurred to me that not every picture in the folders this script would be used with would have the same number of keywords, but that the common element in every set of keywords would be their delimiter. It's already common practice in GUI apps to use a comma, so the earlier script was written to count them and return their number with grep and sed. I confess I disregarded CW with that wc -- I found the line on a forum where the question was "How do you count specific elements in a string of text?" In this script, I'd still like to be able to count the commas in the nested 'while' loop (or a 'for' or 'case/esac' loop if either of those are faster at the draw), since the fact remains that file gooberfoo.jpg and file RonaldMcDonald.jpg, just to use some off-the-cuff examples, are likely to have a different number of keywords. I thought I had adequately isolated the second part of the string read in from the text file by the time that loop-inside-the-loop (is the proper term here "nested"?) was run with the "taxt=`echo $n | cut -d: -f2` " command. If I keep a while loop here, where should I put the b variable so that it starts at 1 and increments with that loop and that loop quits when b reaches the same number as the number of commas in the part of the string evaluated within the variable taxt? (that's text with an "a", btw) BZT Just for the sake of argument, here's a text string of the type that appears in the file keywords: Code:
guineabissaubeach.jpg:beach,daytime,mid-coast,summer,stay,vacation |
So my general philosophy here would be KISS (keep it simple silly). I don't know a lot about exiv2 but the below worked for me based on your input:
Code:
#!/bin/bash |
Simple is best -- many thanks.
grail,
Thanks a bunch. With one minor tweak ("add" instead of "set" in the exiv2 command), it worked. "set" in exiv2 is for IPTC, EXIF, and XMP fields and elements that are one-liners (like Date & Time, Caption Writer or Location) "add" is for lists like keywords and supplemental categories, contacts, revision dates, and the like. Hey, like you said, you weren't familiar. No big cheese. :) Again, thanks. Lucky me -- two issues posted in as many days and solved likewise. 8) BZT |
No probs ... glad we could help. Please remember to mark as SOLVED :)
|
Just one more niggling little thing. I could almost answer this question myself, but I want to be sure of my ground before I do.
My own practice with IPTC supplemental categories has been to use a list of words that, by comparison with the one for keywords, is only a few shades different. Both are the lists I've generated in, and carried over several version upgrades for use with, iView Media Pro (now MS Expression Media, the first release of version 2 of which I now have and use with these lists). I presume that to write a script to introduce the "supp cats" into these JPEGs, the only changes necessary would be to change the name of the file read in by the sed command and the field written to by the exiv2 -M"add..." one; everything else should work as is. BZT |
Sounds plausible, but like all good programming, you should test on a copy first to make sure you are on the right path :)
Good luck. |
Getting ambitious
Of course, of course.
I hope it doesn't break any rules or conventions to continue this thread along mainly the same lines as the OP and subsequent posts. This morning I got ambitious and wrote up a single-line text file that had both Keywords and Supplemental Categories on the same line, following the filename (with path) as I gave in my example (post from the 17th), and delimited by a semicolon instead of a colon from the preceding array of keywords. I introduced another for/do/done loop thusly: Code:
for j in $(sed 's/[:,]/ /g' listannots) BZT |
Sorry ... you will have to dumb it down for me a little.
Try showing what is in listannots so I can follow your logic. Maybe also show what the following line should look like in your mind based on the input from the file: Code:
exiv2 -M"add Iptc.Application2.SuppCategory String $j" $thefile |
Quote:
I imagined that Code:
exiv2 -M"add Iptc.Application2.SuppCategory String $j" $thefile Here's the kind of line that appears in listannots: Code:
guineabissaubeach.jpg:beach,daytime,mid-coast,summer,stay,vacation;beach,day,midcoast,midday,summer,Sunday,vacation,warm BZT |
So the issue you have is that sed will make its changes to the whole line and so the for loop looks at the complete line now broken into pieces.
As you have now a need split the initial line and then act on the two separate halves, I came up with the following: Code:
#!/bin/bash |
Now the first script won't work.
I'm referring to grail's post from the 7th -- or rather the script I made from it which worked when it was new:
Code:
#!/bin/bash :confused: BZT Edit1: It's writing again -- as you see above, I had a very old save with "set" instead of "add" in the Exiv2 command and was using that (egg on face). But I also just now noticed the script isn't strictly delimiting by colons and commas -- in one file in a small set I just ran it on, the single keyword entry "cute ass" got split into "cute" (comma)"ass" and put on two lines: split at the space, I'm presuming. Maybe customizing the $IFS would help with that? Edit2: Customizing IFS didn't do any good -- neither did setting off each keyword for that file in double-quotes. After writing to that one file, having cleared the original keywords twice, between the sed and Exiv2 "cute ass" became "cute,ass", and it was the one and only keyword (one word or two) surrounded by quotes. I think I need a serious for-ID10Ts explanation of sed. NE1 know where I can get one for cheap? :) |
Getting back to concept
Putting it in both broad and narrow terms, and including the rules-of-thumb for formatting I apply to my directory lists, this is what a script like this would have to do with a text file list of files in one directory:
1. Read in the filename. The filename is set off from the keywords by a colon. Code:
/cygdrive/c/blu/newest/five/amanor-1005-005.jpg: Code:
adult,cute,cute ass,indoor,naked,redhead Code:
for x in $(ls $(key) | wc -l); do;done Can this be done in BASH? I'm beginning to doubt it. BZT |
I think I've got it:
Code:
#!/bin/bash I almost went with a while loop for the whole thing, to keep track of the total number of files worked on (file w of X), and echo that back to the user along with the "Finished this one" kind I did add, but all-of-a-sudden I blanked on how to replace a "while read" command/expression. BZT |
All times are GMT -5. The time now is 04:18 PM. |