views:

60

answers:

2

As a bash script rookie, detailed answers would be appreciated. :)

I am trying to write a bash script that parses JPEG EXIF time stamps output from the exiv2 commmandline utility, which gives me typical output like:

Image timestamp : 2010:07:27 17:38:52

Is there a way to parse the time stamp so that its components, like year, month, day, hour, minute, second, go into respective variables?

Would sed/gawk be the way to go? If so, how? Or is some other way better?

This way, I can manipulate or mix and match them however I like.

Here is the script I've got so far:

#!/bin/bash

COUNT=0
SKIPPED=0
FILES=0 # number of files encountered

# declare variables for time stamp

YEAR=0
MONTH=0
DAY=0

HOUR=0
MINUTE=0
SECOND=0

for CURRENT_FILE in * # a for loop to go through all files in current directory
do
    if [ -f "$CURRENT_FILE" ] # see if CURRENT_FILE is a file
    then
        FILETYPE=$(file -b --mime-type "$CURRENT_FILE") # get file type
        if [[ $FILETYPE == image/jpeg ]] # see if CURRENT_FILE's mime is image/jpeg
        then
            ((COUNT++))
            echo "Processing file $COUNT: $CURRENT_FILE"
            exiv2 "$CURRENT_FILE" | grep timestamp >> list
        else
            ((SKIPPED++))
            echo "Skipping file $CURRENT_FILE....."
        fi
        ((FILES++))
    fi
done

echo "Encountered $FILES files"
echo "Processed $COUNT files"
echo "Skipped $SKIPPED files"

Thanks!

+4  A: 

Here is a pure bash solution for splitting the timestamp specification line:

SPEC='Image timestamp : 2010:07:27 17:38:52'
read X X YEAR MONTH DAY HOUR MINUTE SECOND <<<${SPEC//:/ }
echo $YEAR
echo $MONTH
echo $DAY
echo $HOUR
echo $MINUTE
echo $SECOND

The solution above converts colons to spaces in the specification, splits it on whitespace, and puts each item in the respective variable.

A solution involving awk, sed or Perl would be similar, implementing the timestamp splitting in one of those languages.

I recommend the pure bash solution though, because it's faster (doesn't have to spawn a subprocess), and it doesn't have external dependencies. Nowadays (compared to the Bourne Shell in the 1970s) most of the string and array manipulation can be done in bash itself, without having to fork and exec expr, tr, sed, awk, perl, cut etc.

With Perl:

SPEC='Image timestamp : 2010:07:27 17:38:52'
read X X YEAR MONTH DAY HOUR MINUTE SECOND <<<$(perl -pe 'y@:@ @' <<<$SPEC)
echo $YEAR
echo $MONTH
echo $DAY
echo $HOUR
echo $MINUTE
echo $SECOND

With tr:

SPEC='Image timestamp : 2010:07:27 17:38:52'
read X X YEAR MONTH DAY HOUR MINUTE SECOND <<<$(tr : ' ' <<<$SPEC)
echo $YEAR
echo $MONTH
echo $DAY
echo $HOUR
echo $MINUTE
echo $SECOND

With sed:

SPEC='Image timestamp : 2010:07:27 17:38:52'
read X X YEAR MONTH DAY HOUR MINUTE SECOND <<<$(sed 's/:/ /g' <<<$SPEC)
echo $YEAR
echo $MONTH
echo $DAY
echo $HOUR
echo $MINUTE
echo $SECOND

With AWK:

SPEC='Image timestamp : 2010:07:27 17:38:52'
read X X YEAR MONTH DAY HOUR MINUTE SECOND <<<$(awk '{gsub(/:/," ");print}' <<<$SPEC)
echo $YEAR
echo $MONTH
echo $DAY
echo $HOUR
echo $MINUTE
echo $SECOND
pts
That's amazing. THANK YOU so much for the quick and very detailed answer!!! :)
penyuan
That is a really great answer.
drewk
Here's a simpler version of `split_timestamp`: `split_timestamp () { local S=(${1//:/ }); echo ${S[@]:2}; }`
Dennis Williamson
+2  A: 

Here's another way

s="Image timestamp : 2010:07:27 17:38:52"
$ IFS="[: ]"
$ set -- $s
$ echo $3
2010
$ echo $4
07
$ echo $5
27
$ echo $6
17
$ echo $7
38
$ echo $8
52
ghostdog74
You don't need the [ and ] in IFS. Make it a function, and make IFS a local variable.
pts