5

I am using openscad commands on Ubuntu linux to generate models from command line. I finaly was successful at running openscad commands using the -D parameters to override variables values :

$ openscad -o output.stl -D 'param1="name1"' -D 'param2="name2"' openscad-script.scad

EDIT: Notice the way we have to pass -D parameters, both single quotes and double quotes have to be there according to the because the Openscad documentation.

But when I generate & execute the same command from a shell script, openscad fails with error :

$ ./myscript.sh value1 value2 

ERROR: Parser error in line XX: syntax error Can't parse file 'openscad-script.scad'!

Where XX = last line of file.

Here is the bash script

#!/bin/bash
# run openscad command
param1="-D 'param1=\"$1\"'"
param2="-D 'param2=\"$2\"'"
echo "openscad -o $1-$2.stl $param1 $param2 openscad-script.scad"
openscad -o $1-$2.stl $param1 $param2 openscad-script.scad

This looks so simple I still cannot figure out what make openscad fail at running the command.

Thanks for your help,

EDIT : I found a way to make it work, may not be the best

#!/bin/bash
# run openscad command
param1="-D 'param1=\"$1\"'"
param2="-D 'param2=\"$2\"'"
command = "openscad -o $1-$2.stl $param1 $param2 openscad-script.scad"
eval $command
jbheren
  • 516
  • 3
  • 11
  • [BashFAQ #50](http://mywiki.wooledge.org/BashFAQ/050) is directly on-point. – Charles Duffy Nov 20 '16 at 16:59
  • Why do you want to manually quote your string parameters in your shell script? Edit: Since you know you want to pass string parameters, you could quote them when calling instead, and your script would be a one-liner. – kintel Nov 20 '16 at 17:08
  • 1
    @Jean-BaptisteHeren To clarify a potential misunderstanding: You only need to pass double quotes around parameter values to OpenSCAD for _string_ parameters. If you want to pass numbers, lists, booleans etc., you simply have to pass the corresponding literals. The parameters are interpreted as scad code. – kintel Nov 20 '16 at 17:53

2 Answers2

5

If your intended command line is:

openscad -o name1-name2.stl -D 'param1="name1"' -D 'param2="name2"' openscad-script.scad

...then a correct script to do this would be:

#!/bin/bash
openscad \
  -o "$1-$2.stl" \
  -D "param1=\"$1\"" \
  -D "param2=\"$2\"" \
  openscad-script.scad

...or, if you really want to build things up over multiple lines for whatever reason:

#!/bin/bash

args=( -o "$1-$2.stl" )
args+=( -D "param1=\"$1\"" )
args+=( -D "param2=\"$2\"" )

openscad "${args[@]}" openscad-script.scad

openscad literally has no way of knowing if single-quotes or double-quotes was used at the command line, so there is no enforceable way for it to require single-quotes. Moreover, shell quoting is a character-by-character attribute! That is to say:

'param1="name1"' # becomes the C string "param1=\"name1\""

results in exactly the same string being passed as:

param1='"name1"' # becomes the C string "param1=\"name1\"", same as above

or

param1='"'name1'"' # becomes the C string "param1=\"name1\"", same as above

...when those values are all constant. When name1 is replaced with something like $1, however, then the meaning becomes very different based on the type of quotes in use:

set -- name1; IFS=0123456789
"param1=\"$1\"" # becomes the C string "param1=\"name1\"", as above
'param1="$1"'   # becomes the C string "param1=\"$1\"", not substituting name1

# ...and, as an example of something to look out for:
param1='"'$1'"'  # becomes TWO C strings, "param1=\"name" and "\"", due to bad quoting
# ...the IFS above makes it split on numbers; by default this risk would happen with spaces
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
3

By writing param1="-D 'param1=\"$1\"'", I suppose you expected that later when you $param1, the embedded double-quotes will be re-evaluated when you run the openscad ... $param1 command. But no, that won't happen.

To achieve what you want, a solution that will work and is clean is using a Bash array:

#!/bin/bash
params=(-D param1="\"$1\"" -D param2="\"$2\"")
printf '%q ' openscad -o "$1-$2".stl "${params[@]}" openscad-script.scad; echo
openscad -o "$1-$2".stl "${params[@]}" openscad-script.scad

I also double-quoted $1-$2, as it is recommended to prevent globbing and word splitting.

janos
  • 120,954
  • 29
  • 226
  • 236
  • Thanks @janos, the need was related to the way openscad wants us to write parameter values. Each var=value couple behind -D option must be single quoted. Of course if I add single quotes around the `param1="$1"`, then $1 will not be evaluated. – jbheren Nov 20 '16 at 16:49
  • @Jean-BaptisteHeren I do get that you need the values quoted. And the script I proposed does that. It's equivalent to your update, within using `eval`. – janos Nov 20 '16 at 16:54
  • Sure @janos, I tried your solution and it gives the following result `openscad -o value1-value2.stl -D 'param1=value1' -D 'param2=value2' openscad-script.scad` But I also need the double quotes inside the command : `openscad -o value1-value2.stl -D 'param1="value1"' -D 'param2="value2"' openscad-script.scad`. I know its weird, sorry if its not clear :) – jbheren Nov 20 '16 at 16:56
  • @Jean-BaptisteHeren, re: "must be single quoted", OpenSCAD has no way of knowing if it was single-quoted or double-quoted; the quotes are evaluated and removed by the shell in the course of building an array of arguments to pass to the `exec()` call starting the external program. – Charles Duffy Nov 20 '16 at 17:03
  • @Jean-BaptisteHeren, ...all UNIX commands receive of their argument list is a single array of NUL-delimited C strings; what quoting or escaping was passed to the shell to tell it how to form that array is no longer visible once the command is run. – Charles Duffy Nov 20 '16 at 17:04
  • The `echo` is a bit misleading. I'd suggest `printf '%q ' openscad -o "$1-$2".stl "${params[@]}" openscad-script.scad"; echo`, so you get a debug line that will literally behave the same as the real command if copied-and-pasted. – Charles Duffy Nov 20 '16 at 17:12
  • Thanks @CharlesDuffy, amended – janos Nov 20 '16 at 17:23
  • Err. I suggested the `printf %q` *with the same quoting you use for the actual command* -- it's going to be escaping *every* space, not just the literal ones, if you quote the whole command as a single argument to `printf`. Try running the printf I gave above after `set -- "file one" "file two"`, and compare. – Charles Duffy Nov 20 '16 at 17:25
  • I missed that. Thanks again @CharlesDuffy – janos Nov 20 '16 at 17:30
  • @Jean-BaptisteHeren I missed the doubly quoting there. Fixed it. – janos Nov 20 '16 at 17:30