0

I want to perform a shell command like this:

convert input.png -pointsize 40 -font "$HOME/Library/Fonts/Droid Sans.ttf" \
 -background black -fill red -stroke blue label:"Foo Bar" \
 -gravity center -composite output.png

But it's part of a script and some elements are dynamic, which I get from a function. Basically I'm trying something like this:

function GetTextCommands {
  echo "-pointsize $2 -font \"$HOME/Library/Fonts/$1.ttf\" \
   -background black -fill red -stroke blue label:\"$3\" \
   -gravity center -composite"
}

bla=$(GetTextCommands "Droid Sans" 40 "Foo Bar")
convert input.png $bla output.png

However I keep getting quote-related trouble with this. Either it doesn't recognize the Sans.ttf part, thinking it's a different argument. Or if I put quotes around the $bla variable in the convert command, it interprets the entire thing as one argument (which is then deemed invalid, of course).

Note that if I put an echo before the convert command to preview what my command line actually looks like, it looks exactly the way I intend. But I realize some quoting may disappear when the entire line is being echo'd.

What's the correct way of going about this?

William Pursell
  • 204,365
  • 48
  • 270
  • 300
RocketNuts
  • 9,958
  • 11
  • 47
  • 88

2 Answers2

3

Rather than trying to generate a string to execute (which would need to be passed to eval, and perhaps the solution you are looking for is simply to invoke eval convert input.png "$bla" output.png, but there are pitfalls so I don't recommend it), just make the call in your function:

function ExecTextCommands {
  convert input.png "$1" -pointsize "$2" -font "$HOME/Library/Fonts/$1.ttf" \
   -background black -fill red -stroke blue label:"$3" \
   -gravity center -composite output.png
}

ExecTextCommands "Droid Sans" 40 "Foo Bar"
William Pursell
  • 204,365
  • 48
  • 270
  • 300
  • Yes, I considered this as well, but my example above is actually a simplified version of a more complex situation, where I have _multiple_ variable parts in the command line, coming from _multiple_ functions. `eval` sounds useful though, would you have any indicator to the pitfalls you mentioned? – RocketNuts Sep 06 '17 at 14:10
2

One correct way is to have your function populate a global array that contains the arguments:

getTextCommands () {
    args=(
      -pointsize "$2"
      -font "$HOME/Library/Fonts/$1.ttf"
      -background black
      -fill red
      -stroke blue
      "label:$3"
      -gravity center
      -composite
    )
}

getTextCommands "Droid Sans" 40 "Foo Bar"
convert input.png "${args[@]}" output.png

One drawback is that using getTextCommands requires you to know the name of the variable it sets.

chepner
  • 497,756
  • 71
  • 530
  • 681