LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   BASH: Help with formatting Output from a script (https://www.linuxquestions.org/questions/programming-9/bash-help-with-formatting-output-from-a-script-828024/)

SilversleevesX 08-23-2010 12:01 PM

BASH: Help with formatting Output from a script
 
When annotating jpegs, whether newly-downloaded or on their way to being backed up to CDs/DVDs, I like to use the same 7 IPTC tags, and also on occasion Keywords and Supplemental Categories. Here's a list of the six:
  1. Category
  2. Credit
  3. Source
  4. Caption Writer
  5. Transmission Reference
  6. Fixture ID (also known as Event or Job ID)
    I use ObjectName as a 'clone' of this for GUI apps like IrfanView that don't "read" JobID in.
  7. Location (IIM V.4 labels it "Sublocation")

Here's the script I have:
Code:

#!/bin/bash
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")

for file in $(ls *.jpg);
do
        echo
#9-point check:
        cate=$(exiv2 -g Iptc.Application2.Category -Pv $file)
        cred=$(exiv2 -g Iptc.Application2.Credit -Pv $file)
        sour=$(exiv2 -g Iptc.Application2.Source -Pv $file)
        writ=$(exiv2 -g Iptc.Application2.Writer -Pv $file)
        trans=$(exiv2 -g Iptc.Application2.TransmissionReference -Pv $file)
        fixid=$(exiv2 -g Iptc.Application2.FixtureId -Pv $file)
        objnm=$(exiv2 -g Iptc.Application2.ObjectName -Pv $file)
        locn=$(exiv2 -g Iptc.Application2.SubLocation -Pv $file)
        keys0=$(exiv2 -g Iptc.Application2.Keywords -Pv $file)
        cats0=$(exiv2 -g Iptc.Application2.SuppCategory -Pv $file)
#Now tell the people:
echo -e "File $file:"
echo -ne "$file:  ">>favesmissing.txt
        if [ -n "$cate" ]; then
                echo -e "HAS a Category tag,"
        else
                echo -e "DOESN'T HAVE a Category tag,"
                echo -ne " Category Tag">>favesmissing.txt
               
        fi
        if [ -n "$cred" ]; then
                echo -e "HAS a Credit tag,"
        else
                echo -e "DOESN'T HAVE a Credit tag,"
                echo -ne " Credit Tag">>favesmissing.txt
        fi
        if [ -n "$sour" ]; then
                echo -e "HAS a Source tag,"
        else
                echo -e "DOESN'T HAVE a Source tag,"
                echo -ne " Source Tag">>favesmissing.txt
        fi
        if [ -n "$writ" ]; then
                echo -e "HAS a Caption Writer tag,"
        else
                echo -e "DOESN'T HAVE a Caption Writer tag,"
                echo -ne " Writer Tag">>favesmissing.txt
        fi
        if [ -n "$trans" ]; then
                echo -e "HAS a Transmission Reference tag,"
        else
                echo -e "DOESN'T HAVE a Transmission Reference tag,"
                echo -ne " Transmission Reference Tag">>favesmissing.txt
        fi
        if [ -n "$fixid" ]; then
                echo -e "HAS an Event/Fixture Identifier tag,"
        else
                echo -e "DOESN'T HAVE an Event/FixtureIdentifier tag,"
                echo -ne " Fixture Id Tag">>favesmissing.txt
        fi
        if [ -n "$objnm" ]; then
                echo -e "HAS an Object Name tag,"
        else
                echo -e "DOESN'T HAVE an Object Name tag,"
                echo -ne " Object Name Tag">>favesmissing.txt
        fi
        if [ -n "$locn" ]; then
                echo -e "HAS a Location tag,"
        else
                echo -e "DOESN'T HAVE a Location Name tag,"
                echo -ne " Location Tag\n">>favesmissing.txt
        fi
        if [ -n "$keys0" ]; then
                echo -e "HAS Keywords,"
                echo -ne "Has Keywords">>favesmissing.txt
        else
                echo -e "DOESN'T HAVE Keywords,"
        fi
        if [ -n "$cats0" ]; then
                echo -e "and HAS Supplemental Categories."
                echo -ne " * Has Supp. Cats.\n">>favesmissing.txt
        else
                echo -e "but DOESN'T HAVE Supplemental Categories."
        fi
done
IFS=$SAVEIFS

This much works splendidly in stdout.
The kind of Output I'm trying to avoid seeing (and having to edit in advance of processing with another script) looks lie this:
Code:

bh_07498_015.jpg:  Has Keywordsbh_07710_007.jpg:  Has Keywordsbh_07710_009.jpg: 
bh_09035_016.jpg:  bh_09035_018.jpg:  bh_09071_004.jpg:  bh_09071_006.jpg: 
bh_09071_010.jpg:  bh_09071_012.jpg:  bh_7498_015.jpg: 
bh_7710_04.jpg:  bizarrepic2029.jpg:  Has Keywords * Has Supp. Cats.

(the above output all to one line without breaks)
...and also the more-than-occasional ones of these:
Code:

1608.jpg:  Fixture Id Tag Location Tag
Has Keywords * Has Supp. Cats.

I believe I'm looking at either a case/esac loop or a function, because in order (as I see the problem) for the script to Output discrete lines that begin with a filename and end with the last IPTC tag that's missing from file X.jpg,everything about the file must be known before dumping it all to the ASCII file. As I've never written either of the length and detail that are obviously required in this case, and because I'm almost sure "the longer they are, the more finely-tailored they have to be," I'm looking for assistance in writing 'long & involved' case/esacs or functions from people who've done asmuch.

I hope this provides enough information. Looking forward to considered replies.

BZT

grail 08-23-2010 12:14 PM

Same story as always, show us what you have tried and where you are getting stuck?

This seems to have been a mammoth task, but I do not seem to be seeing a lot of your input, but mainly questions.
Yes it is a question site but I believe the idea is to learn.

You have also been shown time and again that arrays will probably help if you are storing multiple values for the same file (ie jpg).

As far as case statements go, again show us your ideas and we can help or amend where you may make a mistake.

bluebox 08-23-2010 05:21 PM

Well ... a long script, a long text ...

but, sorry ... I didn't get it.

You wrote a script, don't like the output, so you want a second script to correct the output of the first one? Wouldn't it be better to do things right right of the beginning?

I don't understand, what are your desired results? What are undesired results? What further processing is intended (if there is any)?

What's wrong with
Quote:

Has Keywordsbh_07710_007.jpg
? The absence of a space character? grep doesn't stop this.

What's wrong with
Quote:

Has Keywords * Has Supp. Cats.
?

Let's talk about the basics.

As far as I see, you produce a 10-value-array, consisting of "exists/exists not", associated to a filename.

Quote:

bh_07498_015.jpg: Has Keywordsbh_07710_007.jpg: Has Keywordsbh_07710_009.jpg:
bh_09035_016.jpg: bh_09035_018.jpg: bh_09071_004.jpg: bh_09071_006.jpg:
bh_09071_010.jpg: bh_09071_012.jpg: bh_7498_015.jpg:
bh_7710_04.jpg: bizarrepic2029.jpg: Has Keywords * Has Supp. Cats.
This is really a ugly representation, seen from a programmers point of view!

A much nicer representation would be:

Quote:

bh_07498_015.jpg 0 0 0 0 0 0 0 0 1 0
bh_07710_007.jpg 0 0 0 0 0 0 0 0 1 0
bh_07710_009.jpg 0 0 0 0 0 0 0 0 0 0
bh_09035_016.jpg 0 0 0 0 0 0 0 0 0 0
bh_09035_018.jpg 0 0 0 0 0 0 0 0 0 0
bh_09071_004.jpg 0 0 0 0 0 0 0 0 0 0
bh_09071_006.jpg 0 0 0 0 0 0 0 0 0 0
bh_09071_010.jpg 0 0 0 0 0 0 0 0 0 0
bh_09071_012.jpg 0 0 0 0 0 0 0 0 0 0
bh_7498_015.jpg 0 0 0 0 0 0 0 0 0 0
bh_7710_04.jpg 0 0 0 0 0 0 0 0 0 0
bizarrepic2029.jpg 0 0 0 0 0 0 0 0 1 1
What about rewriting your script to output a file/text similar to this, containing all relevant information easy to use for further processing?

SilversleevesX 08-23-2010 05:58 PM

Quote:

Originally Posted by grail
You have also been shown time and again that arrays will probably help if you are storing multiple values for the same file (ie jpg).

As I see it, it was the "echo -ne" commands in the original script that were responsible for running the this tag is missing incidental phrases into the subsequent filenames. I wanted to avoid that, while at the same time keeping the output nice and "compact." Maybe bluebox's idea of using 1's and 0's is the best way to go about it.

Quote:

Originally Posted by grail (Post 4075248)
As far as case statements go, again show us your ideas and we can help or amend where you may make a mistake.

Rebuilt with case, getting a syntax error (unexpected token, ;; ) on this code:
Code:

#for file in $*.jpg; do
file="strangepic07.jpg"
        case "$file" in
                *.jpg )
                        cate=$(exiv2 -g Iptc.Application2.Category -Pv $file)
                        if [ -n $cate ]; then
                                cate1="HAS a Category Tag"
                        fi
                        cred=$(exiv2 -g Iptc.Application2.Credit -Pv $file)
                        if [ -n $cred ]; then
                                cred1="HAS a Credit Tag"
                        fi
                        sour=$(exiv2 -g Iptc.Application2.Source -Pv $file)
                        if [ -n $cred ]; then
                                sour1="HAS a Source Tag."
                        fi
                        writ=$(exiv2 -g Iptc.Application2.Writer -Pv $file)
                        if [ -n $writ ]; then
                                writ1="HAS a Caption Writer Tag"
                        fi
                        trans=$(exiv2 -g Iptc.Application2.TransmissionReference -Pv $file)
                        if [ -n $trans ]; then
                                trans1="HAS a Transmission Reference tag"
                        fi
                        fixid=$(exiv2 -g Iptc.Application2.FixtureId -Pv $file)
                        if [ -n $fixid ]; then
                                fixid1="Has an Event/Fixture Identifier Tag"
                        fi
                        objnm=$(exiv2 -g Iptc.Application2.ObjectName -Pv $file)
                        if [ -n $objnm ]; then
                                objnm1="HAS an Object Name/Title Tag"
                        fi
                        locn=$(exiv2 -g Iptc.Application2.SubLocation -Pv $file)
                        if [ -n $locn ]; then
                                locn1="HAS a Location Tag"
                        fi
                        keys0=$(exiv2 -g Iptc.Application2.Keywords -Pv $file)
                        if [ -n $keys0 ]; then
                                keys00="HAS Keywords"
                        else
                                keys00="does NOT have Keywords"
                        fi
                        cats0=$(exiv2 -g Iptc.Application2.SuppCategory -Pv $file)
                        if [ -n $cats0 -a -n $keys0 ]; then
                                cats00="and HAS Supplemental Categories."
                        else if [ -n $keys0 -a -z $cats0]; then
                                cats00="but does NOT have Supplemental Categories."
                        fi
        ;;
        esac
        echo -e "File $file:"
        echo -ne "$cate1\n$cred1\n$sour1\n$writ1\n$trans\n$fixid\n$objnm1\n$locn1\n$keys00\n$cats00\n"
#done

NB:At this point, the furthest I've taken it from the original script, besides the case/esac loop, is what is seen in stdout. I don't have it writing anything to text yet.

I commented out the for/do/done to see if it would work on one specific file. Rather than write that filename to its own ASCII text file, I thought to set it to the variable file.

I suppose it's not kosher to have so many if/then/fi's inside a case/esac loop, but I've yet to puzzle out where else to put them. At any rate, rewriting it this way has given me some ideas on how to make the original script work the way I want it, in terms of "dumped" output.

BZT

bluebox 08-23-2010 06:59 PM

SilversleevesX, if all you want is a trailing newline after each tag list, your first script was completely okay. The only thing missing was:
Code:

        fi
 echo
 # write a newline after each for-loop
 # maybe add a echo >> favesmissing.txt
done
IFS=$SAVEIFS

Besides that, you should remove the newlines from " Location Tag\n" and " * Has Supp. Cats.\n" (except there is a special reason for it).

I don't see how a case structure could be useful for you. You have ten if-then-clauses and each has to be processed. "case" is useful if you have ten if-then-clauses but only one "case" has to be processed.

In case we talk about tighten your code, think about this pseudocode:

Code:

for file in $(ls *.jpg);
do
  line=$file" ";
  for i in "Category Credit Source Writer TransmissionReference FixtureId ObjectName SubLocation Keywords SuppCategory"; do
    if [ -n `exiv2 -g Iptc.Application2.$i -Pv $file` ]; then
      line=$line" "${i}" Tag is not missing "
    else
      line=$line" "${i}" Tag is missing "
    fi
  done;
  echo $line;
done

This is written out of my head, untested and will most likely not work out of the shelf!

There a two nested for-loops. The outer one goes through all your files listed by "ls". The inner one goes through your ten if-then clauses, reducing your code.


All times are GMT -5. The time now is 05:32 AM.