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?

Big McLargeHuge
  • 3,044
  • 11
  • 35
  • 49

3 Answers3

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.

heemayl
  • 54,820
  • 8
  • 124
  • 141
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.

mikeserv
  • 57,448
  • 9
  • 113
  • 229
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
iruvar
  • 16,515
  • 8
  • 49
  • 81