Tihomir Mitkov
Tihomir Mitkov

Reputation: 846

Prepare command line arguments in a variable

I need to generate some images using ImageMagick. For this reason I prepare draw operation in variable before actually calling convert, which looks like this

convert -size 160x160 xc:skyblue \
-fill 'rgb(200, 176, 104)' \
$draw_operations \
$0.png 

$draw_operations contains lines, like these

-draw 'point 30,50' \
-draw 'point 31,50'

This call to convert always results in

non-conforming drawing primitive definition `point` ...
unable to open image `'30,50'' ...
...

If I use $draw_operations with double quotes (which is required, if it contains multiple lines) the error is

unrecognized option `-draw 'point 30,50' '

Finally if I simply put -draw 'point 30,50' as is, there is no error. So it's not related to ImageMagick, but rather to the way bash substitute variables.

Upvotes: 3

Views: 715

Answers (2)

terdon
terdon

Reputation: 3380

Use eval instead. That should interpret the spaces and quoting correctly:

#!/bin/bash
draw_operations="-draw 'point 30,50' \
 -draw 'point 31,50'"

eval "convert -size 160x160 xc:skyblue \
-fill 'rgb(200, 176, 104)' \
"$draw_operations" \
    "$0".png"

By the way, a useful debugging trick is to add set -x at the beginning of your script. That will show you what commands are executed and how.


Note that, as @GordonDavisson points out in the comments, eval is dangerous and will execute arbitrary code if, for example, your file name contains shell meta characters. I recommend you use his approach below which is both more elegant and safer.

Upvotes: 2

Gordon Davisson
Gordon Davisson

Reputation: 126098

See BashFAQ 50: I'm trying to put a command in a variable, but the complex cases always fail!. The problem is that the shell parses quotes and escapes before it expands variables, so putting quotes in a variable's value doesn't work -- by the time the quotes "are there", it's too late for them to do any good.

In this case, it looks to me like the best solution would be to store the arguments in an array, and then use "${array[@]}" (including the double-quotes) to add them to the command. Something like this:

draw_operations=(-draw 'point 30,50' -draw 'point 31,50')
# Note that this creates an array with 4 elements, "-draw", "point 30,50",  "-draw", and "point 31,50"

convert -size 160x160 xc:skyblue \
    -fill 'rgb(200, 176, 104)' \
    "${draw_operations[@]}" \
    "$0.png"

You can also build the array incrementally, like this:

draw_operations=()    # Start with an empty array
draw_operations+=(-draw 'point 30,50')    # Add two elements
draw_operations+=(-draw 'point 31,50')    # Add two more elements
...

Upvotes: 4

Related Questions