Prepare command line arguments in a variable

I need to generate some images using ImageMagick. For this reason, I am preparing the drawing operation in a variable prior to the actual call convert

, which looks like this

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

      

$ draw_operations contains lines like this

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

      

This challenge convert

always leads to

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 just put it -draw 'point 30,50'

as is, there will be no error. So it is not specific to ImageMagick, but rather to bash variable substitution.

+3


source to share


2 answers


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

In this case, it seems to me that the best solution would be to store the arguments in an array and then use "${array[@]}"

(including double quotes) to add them to the command. Something like that:

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 in stages, for example:

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
...

      

+4


source


Use eval

instead. This should interpret whitespace and quote 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

to the beginning of your script. This will show you what commands are being executed and how.




Note that since @GordonDavisson points out in the comments, it eval

is dangerous and will execute arbitrary code if, for example, your filename contains shell meta characters. I recommend that you use his approach , which is more elegant and secure.

+2


source







All Articles