0

I'm processing a package of pictures, from which "file" returns the following:

$ file pic.jpg
pic.jpg: JPEG image data, JFIF standard 1.01, resolution (DPI), density 96x96, segment length 16, baseline, precision 8, 231x288, frames 3
$ file pic.jpg | cut -d',' -f8 | tail -c+2
231x288

So I'm picking dimensions in two variables, using built-in "read", before proceeding with cropping.

But something eludes me. Why isn't this construct working...

$ ( file pic.jpg | cut -d',' -f8 | tail -c+2 | IFS=x read width height ; echo w:$width h:$height; )
w: h:

...while this construct is working?

$ ( IFS=x read width height <<< $(file pic.jpg | cut -d',' -f8 | tail -c+2) ; echo w:$width h:$height; )
w:231 h:288

To summarize, why can't I use a pipeline with built-in "read" in that situation?

3 Answers3

3

In bash, the commands in a pipeline are run in subshells (see the last paragraph of Pipelines in the manual). Any variables you declare in a subshell will disappear when the subshell exits.

You can use the { } grouping construct to keep the read and the echo in the same subshell:

file pic.jpg | cut -d',' -f8 | tail -c+2 | { IFS=x read width height ; echo w:$width h:$height; }

This is why the here-string is useful: it runs the read command in the current shell, so the variables are available in the next command.

glenn jackman
  • 238,783
  • 38
  • 220
  • 352
  • This nails the point. Just like I wrote `IFS=x` before `read`, `width` and `height` cannot be forwarded to the parent shell. Thanks for pointing this out! – TallFurryMan Mar 31 '15 at 08:18
1

You can use identify from ImageMagick and do

$ identify -format 'w=%[w]; h=%[h]' file.jpg

notice the use of = and ; so you can do

$ eval $(identify -format 'w=%[w]; h=%[h]' file.jpg)

to set the variables in your shell

Diego Torres Milano
  • 65,697
  • 9
  • 111
  • 134
  • Thanks for the tip! My question focused on the use of `read` in that situation, but your answer is helpful nonetheless. – TallFurryMan Mar 31 '15 at 08:12
0

Actually, as you are using bash, there is an even easier method that only takes one line, no evals, and no cuts and no tails:

read w h < <(identify -format "%w %h" file.jpg)

It really comes into its own when you want to extract many parameters, like the height, width, mean, standard deviation, colourspace, and the number of unique colours etc. all in one call:

read w h m s c u < <(identify -format "%w %h %[mean] %[standard-deviation] %[colorspace] %k" file.jpg)
Mark Setchell
  • 191,897
  • 31
  • 273
  • 432