diff options
author | Steven <steven.vasilogianis@gmail.com> | 2021-11-09 14:21:05 -0500 |
---|---|---|
committer | Steven <steven.vasilogianis@gmail.com> | 2021-11-09 14:38:22 -0500 |
commit | 2ea8f9a13ae0309cc595cbb1316acef52af4afa8 (patch) | |
tree | a87b3cc8d24a6222669e4a08d5608557db0030b3 | |
parent | 4767a828663c3c4820d21c044ed94d2d15952bcd (diff) |
More documentation; parse args with getopt instead of getopts (stole Andy's argument parsing code, he will never know)
-rwxr-xr-x | shopenscad.sh | 306 |
1 files changed, 170 insertions, 136 deletions
diff --git a/shopenscad.sh b/shopenscad.sh index 075290d..4e8f7d0 100755 --- a/shopenscad.sh +++ b/shopenscad.sh | |||
@@ -1,184 +1,218 @@ | |||
1 | #!/bin/bash | 1 | #!/bin/bash |
2 | # shopenscad.sh: parse a .scad file and generate an openscad command with all | 2 | |
3 | # its var=value's parameterized into -D options, which can be overriden with | 3 | #set -x |
4 | # shell variables. | 4 | |
5 | # | 5 | OPENSCAD=${OPENSCAD:-"openscad"} |
6 | # Usage examples: | 6 | RUN=y |
7 | # | 7 | INTERACTIVE= |
8 | # $ ./shopenscad.sh cubbies.scad | 8 | PRINT_VARS= |
9 | # openscad 'cubbies.scad' -D 'part="divider"' -D 'cubby_width=50' -D 'cubby_depth=180' -D 'cubby_divider_height=90' -D 'thickness=5' -D 'strut_thickness=5' -D 'tab_width=10' -D 'tab_padding=5' -D 'tab_tolerance=0.5' -o 'divider=50=180=90=5=5=10=5=0.5.stl' | 9 | USER_OUTPUT_FILENAME= |
10 | # [openscad output omitted] | 10 | SCAD_FILE= |
11 | # | 11 | |
12 | # (the openscad command is printed and then evaluated, outputing to the file | 12 | help() |
13 | # indicated after the -o flag) | 13 | { |
14 | # | 14 | cat <<EOF |
15 | # You can also overwrite the variables parsed from your scad file by passing a | 15 | $0: parse and execute OpenSCAD files, allowing default variables from input scad |
16 | # shell variable with the same name: | 16 | to be overridden with values supplied from the shell. (The parsing of scad |
17 | # | 17 | files is done from the shell mostly with sed, and is very primitive) |
18 | # $ cubby_width=200 part=\"bottom\" ./shopenscad.sh cubbies.scad | 18 | |
19 | # openscad 'cubbies.scad' -D 'part="bottom"' -D 'cubby_width=200' -D 'cubby_depth=180' -D 'cubby_divider_height=90' -D 'thickness=5' -D 'strut_thickness=5' -D 'tab_width=10' -D 'tab_padding=5' -D 'tab_tolerance=0.5' -o 'bottom=200=180=90=5=5=10=5=0.5.stl' | 19 | Usage: $0 [-h] [-n] [-p] [-i] [-o OUTPUT-FILENAME] INPUT.scad |
20 | # [openscad output omitted] | 20 | |
21 | # | 21 | -h, --help display this help |
22 | # Now we can easily generate multiple models: | 22 | -p, --print-vars print variables parsed from INPUT.scad |
23 | # | 23 | -i, --interactive show output command and query for execution |
24 | # $ for w in 250 300 350 400; do | 24 | -n, --no-act show output command, do not execute |
25 | # > for p in '"divider"' '"bottom"'; do | 25 | -o, --output-filename Specify an output filename. The following variables are |
26 | # > cubby_width="$w" part="$p" ./shopenscad.sh cubbies.scad | 26 | available to you: |
27 | # > done | 27 | |
28 | # > done | 28 | \$VALUES - all values from INPUT.scad. This is the |
29 | # [openscad output omitted] | 29 | default: |
30 | 30 | cube-15-10-5.stl | |
31 | openscad=${OPENSCAD:-"openscad"} | 31 | |
32 | 32 | \$ALL - all variable names and values from INPUT.scad: | |
33 | # yes_eval=false | 33 | shape=cube,width=15,height=10,depth=5.stl |
34 | # no_eval=false | 34 | |
35 | 35 | Additionally, all variables parsed from INPUT.scad | |
36 | interactive=false | 36 | are available the associatve array $SCAD, e.g.: |
37 | run=true | 37 | '\${SCAD[part]}.stl' |
38 | print_vars=false | 38 | |
39 | user_output_filename= | 39 | Usage examples: |
40 | 40 | ||
41 | while getopts pino: opt; do | 41 | 1) Run $OPENSCAD with default values from input scad file: |
42 | case $opt in | 42 | |
43 | p) print_vars=true ;; # print variables that were parsed | 43 | $ $0 input.scad |
44 | i) interactive=true ;; # suppress interactive output -- do eval cmd | 44 | |
45 | n) run=false ;; # do not eval cmd | 45 | 2) You can override variables in the input file with variables passed in |
46 | o) user_output_filename="$OPTARG" ;; # override default output filename | 46 | through the shell; this will override "part" and "cubby_width" |
47 | esac | 47 | paramaters from input scad file. (Note that if the part is a string, |
48 | done | 48 | you need to include quotes.): |
49 | shift $(($OPTIND - 1)) | 49 | |
50 | scad_file="$*" | 50 | $ cubby_width=200 part='"bottom"' $0 input.scad |
51 | 51 | ||
52 | if [ ! "$scad_file" ]; then | 52 | |
53 | echo "$0: needs an input scad file" | 53 | 3) Generate multiple models: |
54 | exit 1 | 54 | |
55 | fi; | 55 | $ for w in 250 300 350 400; do |
56 | 56 | cubby_width="$w" part="bottom" $0 cubbies.scad | |
57 | function strip_comments () { | 57 | done |
58 | strip_multiline_comments | 58 | EOF |
59 | } | 59 | } |
60 | 60 | ||
61 | function strip_multiline_comments () { | 61 | parse_options() |
62 | { | ||
63 | OPTS=$(getopt \ | ||
64 | --options 'hpino:' \ | ||
65 | --longoptions 'help,print-vars,interactive,no-act,output-filename:' \ | ||
66 | -- "$@") | ||
67 | eval set -- "$OPTS" | ||
68 | unset OPTS | ||
69 | |||
70 | if [ $# = 0 ]; then | ||
71 | help | ||
72 | exit | ||
73 | fi | ||
74 | |||
75 | while true; do | ||
76 | case "$1" in | ||
77 | -h | --help ) help; exit;; | ||
78 | -p | --print-vars ) PRINT_VARS=y;; | ||
79 | -i | --interactive ) INTERACTIVE=y;; | ||
80 | -n | --no-act ) RUN=;; | ||
81 | -o | --output-filename ) shift; USER_OUTPUT_FILENAME=$1;; | ||
82 | -- ) shift; break;; | ||
83 | esac | ||
84 | shift | ||
85 | done | ||
86 | |||
87 | SCAD_FILE="$*"; | ||
88 | [ -f "$SCAD_FILE" ] || die "$0: Needs an input scad file" | ||
89 | |||
90 | } | ||
91 | |||
92 | die() { printf 'Error: %s\n' "$*" >&2; exit 1; } | ||
93 | warn() { printf 'Warning: %s\n' "$*" >&2; } | ||
94 | |||
95 | strip_multiline_comments () { | ||
62 | # https://stackoverflow.com/questions/13061785/remove-multi-line-comments | 96 | # https://stackoverflow.com/questions/13061785/remove-multi-line-comments |
63 | # https://stackoverflow.com/users/751863/steve | 97 | # https://stackoverflow.com/users/751863/steve |
64 | sed -r ':a; s%(.*)/\*.*\*/%\1%; ta; /\/\*/ !b; N; ba' | 98 | sed -r ':a; s%(.*)/\*.*\*/%\1%; ta; /\/\*/ !b; N; ba' |
65 | } | 99 | } |
66 | 100 | ||
67 | function strip_trailing_semicolon () { | 101 | strip_trailing_semicolon () { |
68 | sed -r 's/;$//' | 102 | sed -r 's/;$//' |
69 | } | 103 | } |
70 | 104 | ||
71 | function strip_leading_spaces () { | 105 | strip_leading_spaces () { |
72 | sed -r 's/^ +//' | 106 | sed -r 's/^ +//' |
73 | } | 107 | } |
74 | 108 | ||
75 | function strip_trailing_spaces () { | 109 | strip_trailing_spaces () { |
76 | sed -r 's/ +$//' | 110 | sed -r 's/ +$//' |
77 | } | 111 | } |
78 | 112 | ||
79 | function strip_nonassignments () { | 113 | strip_nonassignments () { |
80 | grep -e '^[A-Za-z0-9_]\+\s*=' | 114 | grep -e '^[A-Za-z0-9_]\+\s*=' |
81 | } | 115 | } |
82 | 116 | ||
83 | function chomp () { | 117 | chomp () { |
84 | strip_leading_spaces |strip_trailing_spaces | 118 | strip_leading_spaces |strip_trailing_spaces |
85 | } | 119 | } |
86 | 120 | ||
87 | function parse_variable () { | 121 | parse_variable () { |
88 | #sed -r 's/^([a-zA-Z0-9_]+).*/\1/' | 122 | #sed -r 's/^([a-zA-Z0-9_]+).*/\1/' |
89 | sed -r 's/^([^=]+)=.*/\1/' | 123 | sed -r 's/^([^=]+)=.*/\1/' |
90 | } | 124 | } |
91 | 125 | ||
92 | function parse_value () { | 126 | parse_value () { |
93 | #sed -r 's/^.*?=\s*([^;]+);.*$/\1/' | 127 | #sed -r 's/^.*?=\s*([^;]+);.*$/\1/' |
94 | #sed -r 's/^[^=]+\s*=\s*([^;]+);.*$/\1/' | 128 | #sed -r 's/^[^=]+\s*=\s*([^;]+);.*$/\1/' |
95 | sed -r 's/.*=\s*([^;]+?).*/\1/' | 129 | sed -r 's/.*=\s*([^;]+?).*/\1/' |
96 | } | 130 | } |
97 | 131 | ||
98 | function val_to_filename () { | 132 | val_to_filename () { |
99 | echo "$1" |sed -r 's/"//g' |sed -r 's/ /_/g' | 133 | echo "$1" |sed -r 's/"//g' |sed -r 's/ /_/g' |
100 | } | 134 | } |
101 | 135 | ||
102 | function strip_last_char () { | 136 | strip_last_char () { |
103 | echo "$1" |sed -r 's/.$//' | 137 | echo "$1" |sed -r 's/.$//' |
104 | } | 138 | } |
105 | 139 | ||
106 | function strip_after_hidden () { | 140 | strip_after_hidden () { |
107 | echo "$1" |sed -n '/\/\* \[Hidden\] \*\//q;p' cubbies.scad | 141 | echo "$1" |sed -n '/\/\* \[Hidden\] \*\//q;p' cubbies.scad |
108 | } | 142 | } |
109 | 143 | ||
110 | function strip_trailing () { | 144 | strip_trailing () { |
111 | trailing="$1" | 145 | trailing="$1" |
112 | input="$2" | 146 | input="$2" |
113 | echo ${input%${trailing}} | 147 | echo ${input%${trailing}} |
114 | } | 148 | } |
115 | 149 | ||
116 | output_params="" | 150 | main() |
117 | default_output_filename="" | 151 | { |
118 | all="" | 152 | parse_options "$@" |
119 | values_only="" | 153 | |
120 | val_sep="-" | 154 | output_params="" |
121 | var_sep="," | 155 | default_output_filename="" |
122 | 156 | ALL="" | |
123 | declare -A scad | 157 | VALUES="" |
124 | 158 | val_sep="-" | |
125 | while IFS= read -r line; do | 159 | var_sep="," |
126 | [ "$line" ] || continue; | 160 | declare -A SCAD |
127 | clean="$(echo -n "$line" |chomp)" | 161 | |
128 | var=$(echo -n "$clean" |parse_variable |chomp) | 162 | while IFS= read -r line; do |
129 | 163 | [ "$line" ] || continue; | |
130 | # use value provided on command line preferentially to any values in the .scad file | 164 | clean="$(echo -n "$line" |chomp)" |
131 | val="" | 165 | var=$(echo -n "$clean" |parse_variable |chomp) |
132 | if [[ -n "${!var}" ]]; then | 166 | |
133 | val=${!var} | 167 | # use value provided on command line preferentially to any values in the .scad file |
134 | else | 168 | val="" |
135 | val=$(echo -n "$clean" |parse_value |chomp) | 169 | if [[ -n "${!var}" ]]; then |
170 | val=${!var} | ||
171 | else | ||
172 | val=$(echo -n "$clean" |parse_value |chomp) | ||
173 | fi | ||
174 | |||
175 | if [ "$var" ] && [ "$val" ]; then | ||
176 | SCAD[$var]="$val" | ||
177 | output_params+="-D '$var=$val' " | ||
178 | VALUES+="$(val_to_filename "$val")${val_sep}" | ||
179 | ALL+="${var}=$(val_to_filename "$val")${var_sep}" | ||
180 | fi; | ||
181 | done < <(echo "$(cat "$SCAD_FILE")" | | ||
182 | strip_multiline_comments |strip_after_hidden |strip_nonassignments |strip_trailing_semicolon) | ||
183 | |||
184 | if [ "$PRINT_VARS" ]; then | ||
185 | for k in "${!SCAD[@]}"; do | ||
186 | echo ${k}=${SCAD[$k]} | ||
187 | done | ||
188 | exit | ||
136 | fi | 189 | fi |
137 | 190 | ||
138 | if [ "$var" ] && [ "$val" ]; then | 191 | ALL=$(strip_trailing "$var_sep" "$ALL") |
139 | scad[$var]="$val" | 192 | VALUES=$(strip_trailing "$val_sep" "$VALUES") |
140 | output_params+="-D '$var=$val' " | 193 | |
141 | values_only+="$(val_to_filename "$val")${val_sep}" | 194 | default_output_filename="$(strip_trailing "-" "${VALUES}").stl" |
142 | all+="${var}=$(val_to_filename "$val")${var_sep}" | 195 | output_filename="$default_output_filename" |
143 | fi; | 196 | if [ "$USER_OUTPUT_FILENAME" ]; then |
144 | done < <(echo "$(cat "$scad_file")" | | 197 | output_filename=$(echo $(eval "echo $USER_OUTPUT_FILENAME")) |
145 | strip_comments |strip_after_hidden |strip_nonassignments |strip_trailing_semicolon) | 198 | fi |
146 | 199 | ||
147 | 200 | openscad_str="$OPENSCAD '$SCAD_FILE' "$output_params" -o '$output_filename'" | |
148 | if $print_vars; then | 201 | echo "${openscad_str}" |
149 | echo The following variables have been parsed from ${scad_file}: | 202 | |
150 | for k in "${!scad[@]}"; do | 203 | [ ! "$RUN" ] && [ ! "$INTERACTIVE" ] && exit |
151 | echo ${k}=${scad[$k]} | 204 | |
152 | done; echo | 205 | if [ "$INTERACTIVE" ]; then |
153 | fi | 206 | eval_prompt="Evaulate openscad command? (type y for yes, anything else to exit): " |
154 | 207 | read -p "$eval_prompt" -n1 yes_eval_read | |
155 | #all=$(strip_trailing "$val_sep" "$all") | 208 | echo |
156 | values_only=$(strip_trailing "$val_sep" "$values_only") | 209 | case "$yes_eval_read" in |
157 | 210 | [Yy]) RUN=y ;; # still true | |
158 | default_output_filename="$(strip_trailing "-" "${values_only}").stl" | 211 | *) RUN=;; |
159 | output_filename="$default_output_filename" | 212 | esac |
160 | if [ "$user_output_filename" ]; then | 213 | fi |
161 | output_filename=$(echo $(eval "echo $user_output_filename")) | 214 | |
162 | fi | 215 | [ "$RUN" ] && eval "$(echo "$openscad_str")" |
163 | 216 | } | |
164 | #openscad_str="$openscad "$scad_file" "$output_params" -o $(strip_trailing "-" "${values_only}").stl" | 217 | |
165 | openscad_str="$openscad '$scad_file' "$output_params" -o '$output_filename'" | 218 | main "$@" |
166 | #openscad_str="$openscad '$scad_file' "$output_params" -o '${all}.stl'" | ||
167 | |||
168 | # ${open_filename//'/'\\''} | ||
169 | |||
170 | |||
171 | echo "${openscad_str}" | ||
172 | $print_vars || ! $run && ! $interactive && exit | ||
173 | |||
174 | if $interactive; then | ||
175 | eval_prompt="Evaulate openscad command? (type y for yes, anything else to exit): " | ||
176 | read -p "$eval_prompt" -n1 yes_eval_read | ||
177 | echo | ||
178 | case "$yes_eval_read" in | ||
179 | [Yy]) run=true ;; # still true | ||
180 | *) run=false ;; | ||
181 | esac | ||
182 | fi | ||
183 | |||
184 | $run && eval "$(echo "$openscad_str")" | ||