3

The output from exif looks like this:

ExifMnoteCanon: Loading entry 0xcf27 ('(null)')...
ExifMnoteCanon: Loading entry 0x3ca8 ('(null)')...
ExifMnoteCanon: Loading entry 0xf88a ('(null)')...
2013:08:22 18:01:16

In my bash script, I store this in a variable:

datetime="$(exif --debug --machine-readable --tag=DateTimeOriginal "$file" 2>&1)"

I want to extract the last line of this using bash parameter substitution. I thought this would work:

datetime="${datetime##*\n}"

But the output is then:

ull)')...
2013:08:22 18:01:16

Why doesn't this work and how can I fix it?

3 Answers 3

4

Use ANSI C style escape sequence, $'\n' to indicate newline:

% echo "$datetime"       
ExifMnoteCanon: Loading entry 0xcf27 ('(null)')...
ExifMnoteCanon: Loading entry 0x3ca8 ('(null)')...
ExifMnoteCanon: Loading entry 0xf88a ('(null)')...
2013:08:22 18:01:16

% echo "${datetime##*\n}"
ull)')...
2013:08:22 18:01:16

% echo "${datetime##*$'\n'}"
2013:08:22 18:01:16

As you can see otherwise \n is being treated as literal n.

2

While $'' is pretty portable these days (BSD sh supports if, for example, though its downstream fork dash does not), POSIXLY:

eval 'printf "%s\n" "${datetime##*"'"$(printf '\n"')}\""

...will work, even if it is annoying. I typically keep a newline in an $nl variable, though, and so:

printf "%s\n" "${datetime##*$nl}"

...is far more manageable. And of course you can just do:

printf "%s\n" "${datetime##*"
"}"

...but it's a little funny looking, maybe.

2

Alternately, with a recent version of bash you could use mapfile and process substitution to store exif output into an array and then access the last element

mapfile -t arr < <(
         exif --debug --machine-readable --tag=DateTimeOriginal "$file" 2>&1)
printf '%s\n' "${arr[@]:(-1)}"
2013:08:22 18:01:16
1
  • hmmm... i dont speak french, but planets are cool.
    – mikeserv
    Dec 26, 2015 at 5:59

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .