I'm constructing a command line for use with the 'mogrify' tool [part of imagemagick]. the finalised command line looks something like this :

mogrify -stroke yellow -draw 'line 0,0 0,319' -draw 'line 125,0 125,319' -draw 'line 652,0 652,319' file.png

I echo the command before executing it. If I copy/paste this echo'd line as a new command, exactly as written, directly into the shell, it works perfectly.

However, it doesn't work within the script. for some reason, mogrify looks for a files named 0,0, 0,319, etc. It's obvious that mogrify is interpreting the draw argument strings as though there were no single-quotes around them.

The final command given [i.e., the line in the script where the error occurs] is :

mogrify -stroke $C3 $args $FILE

I construct the string $args iteratively. the result of the final string is what I've put near the top of this question.

I've tried escaping the single quotes with backslash within the construction loop, double-escaping with double-quoted single quotes, swapping single and double quotes. I've also tried placing $args in double-quotes. I've even tried putting each argument into an array and then using ${args[@]} within the final call [where $args is above]. Nothing I've tried works.

[EDIT - showing further information for the array-style invocation]

for the array invocation, i prepare the array as follows :

data="99.8734 351.645 1836.05"
for p in $data; do
    x=$(echo "$W * $p / $duration" | bc)
    args+=(-draw "'line $x,$y1 $x,$y2'")

[nota : the $data are actually retrieved from an external source, but for purposes of this question i am assigning the data points literally here.]

when i make the call to mogrify using the array invocation, i issue the following command in the script : mogrify -stroke $C3 "${args[@]}" $FILE

in this case, neither $C3 nor $FILE have any whitespace.

the errors i get from the above look like the following : mogrify: non-conforming drawing primitive definition 'line 35,0 35,320' @ error/draw.c/RenderMVGContent/4271

so it seems the array assignment is working correctly now, but the shell is passing something inappropriate to mogrify.

when i echo the exact command line, the following is displayed : mogrify -stroke yellow -draw 'line 35,0 35,319' -draw 'line 125,0 125,319' -draw 'line 652,0 652,319' file.png

interestingly, when i change the array assignment to the following, moving the double quotes around the whole thing instead of just the line definitions : args+=("-draw 'line $x,$y1 $x,$y2'")

...then mogrify gives me the following error : mogrify: unrecognized option '-draw 'line 35,0 35,319'' @ error/mogrify.c/MogrifyImageCommand/4716

notice that the error output now correctly includes the single-quotes i had put around the line definition, where it didn't before. this gave me the idea to also try escaping the single quotes with '\'', but that doesn't work either. neither does reversing the single and double quotes [of course allowing for variable expansion inside the whole thing].

  • Regarding your recent addition under "EDIT": mogrify does not want the single quotes, and you don't need the single quotes around the line ... argument. That argument is already a single argument due to the double quotes around it. The quoting that you did in the start of the question was just to keep that argument together, to stop the shell from splitting it into multiple arguments on the spaces (the quotes themselves were never passed to mogrify, and they shouldn't be).
    – Kusalananda
    Dec 13 '19 at 10:41

The double (or single) quotes are used to stop the shell processing the text in them. You can't add them as part of the command itself.

What you can do, though, is build up the command using an array, and then include that array variable in the result. Here I've used args as an array variable rather than a scalar (a string), so we can repeatedly append quoted values to its list:


args+=(-draw 'line 0,0 0,319')
args+=(-draw 'line 125,0 125,319')
args+=(-draw 'line 652,0 652,319')


args+=(-draw "line $x,$y1 $x,$y2")

if you use variables in place of literal numbers. Note specifically that the single quotes you have shown in the your updated question are incorrect (this is wrong: args+=(-draw "'line $x,$y1 $x,$y2'") as you will be including the single quote characters in the values that are passed to mogrify).

Finally, double-quote the set of args's values so that each element is treated as a quoted value by the shell:

mogrify -stroke "$C3" "${args[@]}" "$FILE"
  • @Isaac, @roaima it seems the double-quotes around the array makes all the difference in the world. :) thank you for that. however, now there's another problem ; i'm not sure if it's a shell problem any more, or an imagemagick problem. i now get the error mogrify: non-conforming drawing primitive definition 'line 0,0 0,320'. i think it's still a shell issue, as the error changes when i change the quotes. Dec 12 '19 at 16:22
  • @roima basically i'd coded it just the way you had, except i didn't have the double-quotes around the array. your suggestion seems to have solved that issue, but i think the shell is still mis-interpreting the command somehow. i've added some new info after EDIT - showing further information for the array-style invocation that explains how my script creates the array of arguments and how it calls mogrify using those arguments. thanks very much for your help. Dec 13 '19 at 10:44
  • i'll be damned. i expressly included the single quotes inside the double quotes to do just that, since the documentation for imagemagick says they're necessary, and leaving them out when i construct the array results in a command line that, when copied and pasted, gives an error. however, leaving them out as you suggest WORKS. => a new, but related question : how did you arrive at your conclusions ? or, where can i look to educate myself on this particular aspect of scripting so i don't have to ask questions like this in the future ? [already read man pages... @_@ ] Dec 13 '19 at 12:07
  • The quotes are nothing to do with the command. They only exist to tell the shell how to split up and process words on the command line before it passes them to the command. You can also see this, this, and possibly this.
    – roaima
    Dec 13 '19 at 13:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.