From 75d7f06b9a47d7c547b18484d8bd71363101d386 Mon Sep 17 00:00:00 2001 From: Richard Jackson Date: Wed, 12 Apr 2023 08:06:21 +0000 Subject: [PATCH] Adding setup script, new templates and more template logic determinators, fix the standard template, reformatting all scripts. --- README.md | 11 +- auto_shell_scripting/TemplateBuilder.py | 112 ++++++++++++++---- auto_shell_scripting/utils/TemplateLister.py | 37 ++++++ changelog.md | 43 +++++++ img/logo.png | Bin 24792 -> 20151 bytes py2shell.py | 78 ++++++++----- setup.sh | 48 ++++++++ templates/basic.json | 32 +++++ templates/{ex1 => data}/template_data.json | 65 ++++++----- templates/shift/shifting_args.json | 59 ++++++++++ templates/standard.json | 116 ++++++++++--------- 11 files changed, 464 insertions(+), 137 deletions(-) create mode 100755 auto_shell_scripting/utils/TemplateLister.py create mode 100644 changelog.md create mode 100755 setup.sh create mode 100644 templates/basic.json rename templates/{ex1 => data}/template_data.json (53%) create mode 100644 templates/shift/shifting_args.json diff --git a/README.md b/README.md index a617539..a416edc 100644 --- a/README.md +++ b/README.md @@ -45,14 +45,21 @@ ### Example Usage ``` sh # Create a standard script example -$ python ./py2shell.py --output basic.sh --datasource templates/basic.json +$ ./py2shell.py --output basic.sh --datasource basic ``` ``` sh # Create a standard script example and make it executeable -$ python ./py2shell.py --output basic.sh --datasource templates/basic.json --exec +$ ./py2shell.py --output basic.sh --datasource basic --exec ``` +### Advanced Examples +``` sh +# Create an advanced script example and make it executeable +$ ./py2shell.py --output basic.sh --datasource shift::shifting_args --exec +``` + + ### Test your scripts 1. All script you create are saved into a locally generated directory named **scripts**. 2. The previously created script is executed using the following commands. diff --git a/auto_shell_scripting/TemplateBuilder.py b/auto_shell_scripting/TemplateBuilder.py index 1e00763..ace09ec 100755 --- a/auto_shell_scripting/TemplateBuilder.py +++ b/auto_shell_scripting/TemplateBuilder.py @@ -6,6 +6,7 @@ import string import time + @dataclass class TemplateBuilder: value: str @@ -40,14 +41,33 @@ def buildCaseStatement(self, case_statement: dict) -> str: if key == "switch": for val in value: for parameter, statement in val.items(): - switch_array += "\t{}) {};;\n".format(parameter, statement) + switch_array += "\t{}) {};;\n".format( + parameter, statement) statement_builder += "case ${} in\n".format(goal) statement_builder += switch_array statement_builder += "esac\n" return statement_builder + def buildNestedCaseStatement(self, case_statement: dict) -> str: + print("Building, case statement") + switch_array = "" + statement_builder = "" + goal = "" + for key, value in case_statement: + if key == "goal": + goal = value + if key == "switch": + for val in value: + for parameter, statement in val.items(): + switch_array += "\t\t{}) {};;\n".format( + parameter, statement) + statement_builder += "\tcase ${} in\n".format(goal) + statement_builder += switch_array + statement_builder += "\tesac\n" + return statement_builder + def buildForStatement(self, loop_statement: dict) -> str: - print("Building, loop statement") + print("Building, loop statement") statement_builder = "" for_statements = "" goal = "" @@ -73,28 +93,35 @@ def buildWhileStatement(self, loop_statement: dict) -> str: goal = value if key == "run": for k in value: - while_statements += "\t{}".format(self.iterateRun(k)) + if k.keys().__contains__('conditions'): + condition = [_v for _k, _v in k.items()][0] + while_statements += "{}".format( + self.getConditionBuilder(condition)) + else: + while_statements += "\t{}".format(self.iterateRun(k)) if while_statements: statement_builder += "while [ {} ]; do\n".format(goal) statement_builder += while_statements statement_builder += "done\n" return statement_builder - + def getConditionBuilder(self, value) -> str: template = "" for arr in value: # Get Condition Type - condition_type = [ v for k,v in arr.items() ][0] + condition_type = [v for k, v in arr.items()][0] if condition_type == "if": template += self.buildIfStatement(arr.items()) elif condition_type == "case": template += self.buildCaseStatement(arr.items()) + elif condition_type == "case.nested": + template += self.buildNestedCaseStatement(arr.items()) elif condition_type == "for": template += self.buildForStatement(arr.items()) elif condition_type == "while": template += self.buildWhileStatement(arr.items()) return template - + def buildFunction(self, function: dict) -> str: print("Building, function statement") statement_builder = "" @@ -103,19 +130,44 @@ def buildFunction(self, function: dict) -> str: for key, value in function: if key == "name": name = value - if key == "statements": - for stmt in value: + if key == "statements": + for stmt in value: if stmt.keys().__contains__('conditions'): - condition = [ v for k,v in stmt.items() ][0] + condition = [v for k, v in stmt.items()][0] statements += self.getConditionBuilder(condition) else: - statements += self.iterateRun(stmt) + statements += self.iterateRun(stmt) + if key == "control" or key == "onliner": + statements += self.buildOnliner(value) if statements: - statement_builder += "{}(){}".format(name,'{') - statement_builder += "\t" + statements + "\n" + statement_builder += "{}(){}".format(name, '{') + statement_builder += statements + "\n" statement_builder += "}\n" return statement_builder + def replaceMetaTag(self, variable: str) -> str: + variable = variable.replace('__SPACE__', ' ') + variable = variable.replace('__BEGIN__', '\"') + variable = variable.replace('__NEWLINE__', '\\n') + variable = variable.replace('__END__', '\"') + return variable + + def buildControl(self, value: dict) -> str: + line = "" + key = list(value.keys()) + values = list(value.values()) + for v in values[0]: + line += self.replaceMetaTag(v) + return "\n{} {}".format(key[0], line) + + def buildOnliner(self, value: dict) -> str: + line = "" + key = list(value.keys()) + values = list(value.values()) + for v in values[0]: + line += self.replaceMetaTag(v) + return "\n{} {}".format(key[0], line) + def iterateRun(self, template_data: dict) -> str: line_statement = "" run_type = "" @@ -130,33 +182,51 @@ def iterateRun(self, template_data: dict) -> str: elif run_type == "command_call" and key != "type": line_statement += "{} {}\n".format(key, value) except AttributeError as ae: - print("Check datasource syntax and ensure you are using the correct datatype (array, object)") + print( + "Check datasource syntax and ensure you are using the correct datatype (array, object)") print(ae) exit(1) return line_statement def getTemplateData(self, datasource: str) -> dict: template_data = {} - with open(datasource, "r") as f: - template_data = json.load(f) + try: + # Remove extension if present + datasource = datasource.replace('::', '/') + datasource = "templates/{}.json".format(datasource) + if os.path.exists(datasource): + with open(datasource, "r") as f: + template_data = json.load(f) + else: + print("\033[35mWarning: \033[33mMissing or unable to find template (name: {})\033[0m".format( + datasource)) + except Exception as e: + print( + "Error: Missing or unable to find template (name: {})".format(datasource)) return template_data def generate_template(self, template_data: dict) -> str: template = "" for key, value in template_data.items(): + if key in ["purpose"]: + print("\033[36mPURPOSE: \033[33m{}\033[0m".format(value)) # Writes the initial shell - if key in [ "shell.type" ]: + if key in ["shell.type"]: print("Shell Type is {}".format(value)) template += "#!/usr/bin/env {}\n\n".format(value) # template += "set -x\n\n" - elif key in [ "define.variables" ]: + elif key in ["define.variables"]: # Creates a lot of variables - for k,v in value.items(): - template += "{}={}\n".format(k,v) - elif key in [ "conditions" ]: + for k, v in value.items(): + template += "{}={}\n".format(k, v) + elif key in ["conditions"]: # Iterate template += self.getConditionBuilder(value) - elif key in [ "functions" ]: + elif key in ["functions"]: for arr in value: template += self.buildFunction(arr.items()) + elif key in ["control"] or key in ["command_call"]: + template += self.buildControl(value) + elif key in ["onliner"]: + template += self.buildOnliner(value) return template diff --git a/auto_shell_scripting/utils/TemplateLister.py b/auto_shell_scripting/utils/TemplateLister.py new file mode 100755 index 0000000..f395964 --- /dev/null +++ b/auto_shell_scripting/utils/TemplateLister.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3.10 + +from dataclasses import dataclass +import json +import os +import string +import time + + +@dataclass +class TemplateLister: + + def getTemplates(self, path) -> str: + results = [] + purpose = " - " + for entry in os.listdir(path): + full_path = os.path.join(path, entry) + if os.path.isdir(full_path): + results.extend(self.getTemplates(full_path)) + else: + strOutput = open(full_path,"r") + obj = json.loads(strOutput.read()) + try: + purpose += "\033[32m{}".format(obj['purpose']) + except Exception as e: + purpose = " - \033[31m{}".format('missing purpose') + pass + results.append(entry.replace('.json', purpose)) + return results + + def createMenu(self): + counter = 0 + templates = sorted(self.getTemplates("templates")) + print("\033[36m==== Available Templates: ====\033[0m") + for template in templates: + counter += 1 + print("\033[33m{}: \033[35m{}\033[0m".format(counter, template)) diff --git a/changelog.md b/changelog.md new file mode 100644 index 0000000..cde005c --- /dev/null +++ b/changelog.md @@ -0,0 +1,43 @@ +# Changelog + +All notable changes to this project will be documented in this file. + + + +## [1.0.1] - 2023-04-12 + +### Added + +- Adding setup shellscript +- More templates +- More template logic determinators + +### Changed + +- New Project logo +- Fix the standard template +- Reformatting all scripts +- Reformatting all templates + +## [1.0.0] - 2023-01-06 + +### Added + +- Initial Commit + + +[1.1.0]: https://github.com/denezt/automate-shell-scripting/compare/v1.0.0...v1.0.1 +[1.0.0]: https://github.com/denezt/automate-shell-scripting/releases/tag/v1.0.0 \ No newline at end of file diff --git a/img/logo.png b/img/logo.png index f161c45fad64f5a5f6522a6cf8bd0cc22686b99d..3720a94beb15cc3e08ba76c7841bcf6b2855d2fb 100644 GIT binary patch literal 20151 zcmeIaXIN8P&<2Wt3ZhaJkR}KsA_CHT5b3@5rWENQy@P@%9hD|EO7EffA_CHcNDCdL zm(U>u0!i*hJx4v?cc1&~{`+{Ikj>6oYi8b=dDqO^(J(a?*(;Z*FX7r9Uo;=bNS;9Snb!%=!c znwZG)R9aT{lgNW%OjBdsRT6#Q4v8ED6oWP3Jq{ARi6h6`o_{K8a<%<6&L=i+GkFk> z6qOT5%=CU+DXs(IWs><0?$nY`@!Y8epH7zeow@8o4RO>yy41aM!xiFVmXAy2XE2qlxpzYe!^8Q)YdrtHJO5=O)K<7I{&RYiJio$N>}2fWTXan)|1^! zzQb=4J6{RmT@Fni8^vbQPq?WQWcaMj8pAcL$t9|tC(Gw8MRWq?rN}|0W^LTzk z<{`7V=5Huo!j$Yqs57%m3%4mUTYvX{Hm3LTIobS}d~(Zn=0{2|#xfqhCm}4OZjbiX zFPl?H;gY7>=(n!S49{WDewo-+1BEdZh2XiRAv#Q&q1=tG7jO8!@?&Ix3S>CIKv#LZb8q?QQ;8ENo}(?B zyPI7q7I8(2R~aTx1vUCq`W*D66X4tXnW22{g0mZQ>GbG|mR=Bj^_;kYSwvZ|9-GG{ zkr=uTYMg5#FZj$H#<-|%ni$6{720(fMvA82&tp1$-SUxzt=A%5GfERY#3F6l{6Xz7 z>cWQ2JQdj!9~n^Wc`O0$9ocqQ+HN-w7msrf4+GWxnoYPCu~%L?&(S3MlHou!W5SeFFWb%zh3!IM0fLS>mtX6*Tg=^$GG)*l+0I1=oX%{LeuBpXiRBRbOW+VB#P}fon=Hx#c$sTduaCN_U-fXvQnYflS1x4?0KWz zC1XLO5p^0)E1`00<*mvh#U9R@qzNOv+U4wwi9AxJ-$`Up~eTxbaf5KcdX& z{f4k6ucs`QRsBdgU}sHj{zBPsr@A>V(IeYwNMY@WK1! zMMUt+W1U!oh?*WV%7NK{$hd^$G5+ zv zEXVIMaHg%L`z${Ppe6*v+$Dk zN`8s%G{i>*@nYS#fMO)NCr2eiA-^}TA&(`$CJ$oGn@rCBJVB{9mpxN^NM&eiXeNJP zgmy&G)~~A0mfRL$n>dnQ7(2o~qQ9;=95LKGLR?^~u|3LQr)N{jS4-{6dyhBTdg|Ma z;VipoSmfZ>0i%LC+5N_+5DNKT1vb41NR^sh1I(sa)-BRe#cIg=;QRsI0ndS>Lq>HK zzpRL6gOV@Uqv7y*bV78YN|4G&m5_d}G>!{jO3j|#7>`_v#EXPS64%Sr-#31-MK*0P z-COU3kXb#yN_e1vSU)IP^Z#bGei3f91{rqx)?)RXW{fIQ;Jst%`1eQ&EWsuzh{=md zL6-K0^CSshB~K(*s!i>5Y2UMNU1N8LPITvta8zU=W(hys*J0Mq;5sRsKq?oc2{!-IMX&$z5B`gb&ah#ZgIF8 zQyZJqPBdIH5@?ul%WQ~pHC%*k9F9-78PA)*XI7rfy`5KIb8gd|E-ieIU8?BJ^^8Q^Xnjv-e)Bl_*u}r**yETBt#Mk7az9Q%xuOeC z=`Xy$xP#|$;h@xBKdGpxXyt{aQjO6aLstJ$demg+q7+xhbSFKV)xaUk z%)-19DyJC7Y@75{wD_4p?wE-Y<5mx%-#A5tfiQ97tK{CD6~1M=wkW@pVHs5Hfy4__ z3F+2`HNqic3R{ZsOOsE>`t-OnbMI!YCMF#z&3s+f˝`aDSC^PQx%P+3o1u3L7c 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 Q01l44w2D;8qsKx258+Z#k^lez literal 24792 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 diff --git a/py2shell.py b/py2shell.py index 00aeb69..3673121 100755 --- a/py2shell.py +++ b/py2shell.py @@ -1,38 +1,62 @@ +#!/usr/bin/env python + import os import argparse from auto_shell_scripting import TemplateBuilder as TemplateBuilder +from auto_shell_scripting.utils import TemplateLister as TemplateLister # Set Program Parameters -parser = argparse.ArgumentParser(prog='py2shell', description='Tool for automating shell scripts creation') -parser.add_argument('--make-executable', action='store_true', default=False, help='Make script executable') -parser.add_argument('--exec', action='store_true', default=False, help='Make script executable') -parser.add_argument('--datasource', type=str, required=True, help='Path to JSON data source') -parser.add_argument('--output', type=str, required=True, help='Name of target output script name') +parser = argparse.ArgumentParser( + prog='py2shell', description='Tool for automating shell scripts creation') +parser.add_argument('--make-executable', action='store_true', + default=False, help='Make script executable') +parser.add_argument('--exec', action='store_true', + default=False, help='Make script executable') +parser.add_argument('--datasource', type=str, help='Path to JSON data source') +parser.add_argument('--output', type=str, + help='Name of target output script name') +parser.add_argument("--debug", action="store_true", help="Enable debug mode") +parser.add_argument("--templates", action="store_true", + help="Show available templates") + args = parser.parse_args() -print(args) + # Read the JSON file containing the template data datasource = args.datasource output = args.output +view_templates = args.templates + +if args.debug: + print(args) if '__main__' == __name__: - if output.endswith('.sh') and datasource.endswith('.json'): - templateBuilder = TemplateBuilder.TemplateBuilder(value="", collector="") - template_data = templateBuilder.getTemplateData(datasource=datasource) - # Generate the template - template = templateBuilder.generate_template(template_data) - print(template) - # Write the template to a file - if output.endswith('.sh'): - if not os.path.exists("scripts"): - os.mkdir("scripts") - with open("scripts/{}".format(output), "w") as f: - f.write(template) - if args.make_executable or args.exec: - script_name = "scripts/{}".format(output) - if os.path.isfile(script_name): - print("Making, script executeable") - try: - os.chmod("{}".format(script_name),777) - except FileNotFoundError as fnfe: - print(fnfe) - print("Template generated successfully!") + if output is not None and datasource is not None: + try: + if output.endswith('.sh'): + templateBuilder = TemplateBuilder.TemplateBuilder( + value="", collector="") + template_data = templateBuilder.getTemplateData( + datasource=datasource) + # Generate the template + template = templateBuilder.generate_template(template_data) + print(template) + # Write the template to a file + if output.endswith('.sh'): + if not os.path.exists("scripts"): + os.mkdir("scripts") + with open("scripts/{}".format(output), "w") as f: + f.write(template) + if args.make_executable or args.exec: + script_name = "scripts/{}".format(output) + if os.path.isfile(script_name): + print("Making, script executeable") + try: + os.chmod("{}".format(script_name), 777) + except FileNotFoundError as fnfe: + print(fnfe) + print("Template generated successfully!") + except AttributeError as ae: + pass + if view_templates: + t = TemplateLister.TemplateLister() + t.createMenu() diff --git a/setup.sh b/setup.sh new file mode 100755 index 0000000..a5cd76d --- /dev/null +++ b/setup.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +initialize() { + retry=2 + _local_utils=('jq') + for ((i = 0; $i < $retry; i++)); do + apt update -y + for util in ${_local_utils[*]}; do + if [ -z "$(command -v $util)" ]; then + apt-get install $util -y + fi + done + done +} + +usage() { + printf "\033[36mUSAGE:\033[0m\n" + printf "\033[35m$0 \033[33m--action=\033[32mCOMMAND\033[0m\n" + printf "\n" +} + +commands() { + printf "\033[36mCOMMANDS:\033[0m\n" + printf "\033[35mInitial Install \033[32m[ init, initialize, setup, install ]\033[0m\n" + printf "\n" +} + +help_menu() { + printf "\033[36mSetup Py2Shell\033[0m\n" + printf "\033[35mExecute Action \033[32m[ action:COMMAND, --action=COMMAND ]\033[0m\n" + printf "\n" + commands + usage + exit 0 +} + +for argv in $@; do + case $argv in + action:* | --action=*) _action=$(echo $argv | cut -d':' -f2 | cut -d'=' -f2) ;; + -h | -help | --help) help_menu ;; + esac +done + +printf "action:\t$_action\n" + +case $_action in +init | initialize | setup | install) initialize ;; +esac diff --git a/templates/basic.json b/templates/basic.json new file mode 100644 index 0000000..2e2407e --- /dev/null +++ b/templates/basic.json @@ -0,0 +1,32 @@ +{ + "purpose": "A basic BASH shell script.", + "shell.type": "bash", + "define.variables": { + "var1": "Hello", + "var2": "There", + "var3": "Bye", + "var4": "There" + }, + "onliner": { + "printf": [ + "__BEGIN__", + "${var1}", + "__SPACE__", + "${var2}", + "!", + "__NEWLINE__", + "__END__" + ] + }, + "command_call": { + "printf": [ + "__BEGIN__", + "${var3}", + "__SPACE__", + "${var4}", + "!", + "__NEWLINE__", + "__END__" + ] + } +} \ No newline at end of file diff --git a/templates/ex1/template_data.json b/templates/data/template_data.json similarity index 53% rename from templates/ex1/template_data.json rename to templates/data/template_data.json index 62355c6..29f6e28 100755 --- a/templates/ex1/template_data.json +++ b/templates/data/template_data.json @@ -1,27 +1,28 @@ { - "shell.type" : "bash", - "define.variables" : { + "purpose": "A template to test build a generic script.", + "shell.type": "bash", + "define.variables": { "a": "Hello", "b": "Bye", "c": "World", "i": 0, "option": "$1" }, - "conditions" : [ + "conditions": [ { - "type" : "if", - "goal" : "1 == 1", - "run" : [ - { - "type" :"parameter", - "printf":"$a, $b\\n" - } + "type": "if", + "goal": "1 == 1", + "run": [ + { + "type": "parameter", + "printf": "$a, $b\\n" + } ] }, { - "type" : "case", - "goal" : "option", - "switch" : [ + "type": "case", + "goal": "option", + "switch": [ { "-a": "printf 'enter statement for value (-a)\\n'" }, @@ -34,21 +35,23 @@ ] }, { - "type" : "while", - "goal" : "$i -lt 10", - "run" : [ + "type": "while", + "goal": "$i -lt 10", + "run": [ { - "type" : "parameter", + "type": "parameter", "printf": "loop...\\n" - },{ - "type" : "declare", + }, + { + "type": "declare", "i": "$((i+1))" } ] - },{ - "type" : "case", - "goal" : "b", - "switch" : [ + }, + { + "type": "case", + "goal": "b", + "switch": [ { "-a": "printf 'enter statement for value (-a)\\n'" }, @@ -61,18 +64,18 @@ ] }, { - "type" : "for", - "goal" : "i=0; $i < 10; i++", - "run" : [ + "type": "for", + "goal": "i=0; $i < 10; i++", + "run": [ { - "type" : "declare", + "type": "declare", "j": "$((j+1))" - },{ - "type" : "parameter", + }, + { + "type": "parameter", "printf": "loop $j\\n" } ] } ] -} - +} \ No newline at end of file diff --git a/templates/shift/shifting_args.json b/templates/shift/shifting_args.json new file mode 100644 index 0000000..f7daa48 --- /dev/null +++ b/templates/shift/shifting_args.json @@ -0,0 +1,59 @@ +{ + "purpose": "An example of using the shift command to pass parameters.", + "shell.type": "bash", + "define.variables": { + "a": "Hello", + "b": "Bye", + "c": "World", + "i": 0, + "option": "$1" + }, + "functions": [ + { + "name": "help_menu", + "onliner": { + "printf": [ + "__BEGIN__", + "$a", + "__SPACE__", + "$b", + "__NEWLINE__", + "__END__" + ] + }, + "control": { + "exit": [ + "0" + ] + } + } + ], + "conditions": [ + { + "type": "while", + "goal": "$# -gt 0", + "run": [ + { + "type": "parameter", + "printf": "loop...\\n" + }, + { + "conditions": [ + { + "type": "case.nested", + "goal": "1", + "switch": [ + { + "-a": "INPUT=$2;echo -ne \"$INPUT\\n\";shift 2;[ -z \"$2\" ] && exit 0" + }, + { + "*": "help_menu" + } + ] + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/templates/standard.json b/templates/standard.json index 6d62dad..07e865e 100644 --- a/templates/standard.json +++ b/templates/standard.json @@ -1,6 +1,7 @@ { - "shell.type" : "bash", - "define.variables" : { + "purpose" : "Standard script with help menu, conditions and conditional loops.", + "shell.type": "bash", + "define.variables": { "var1": "Hello", "var2": "There", "var3": "Bye", @@ -9,85 +10,88 @@ "option": "$1" }, "functions": [ - { - "name":"help_menu", - "statements": [ - { - "conditions": [ - { - "type" : "if", - "goal" : "1 -gt 1", - "run" : [ + { + "name": "help_menu", + "statements": [ + { + "conditions": [ { - "type" : "parameter", - "printf":"$var1, $var2\\n" + "type": "if", + "goal": "1 -gt 1", + "run": [ + { + "type": "parameter", + "printf": "$var1, $var2\\n" + } + ] } - ] - } - ] - }, - { - "conditions": [ + ] + }, { - "type" : "if", - "goal" : "1 == 1", - "run" : [ + "conditions": [ { - "type" : "parameter", - "printf": "$var3, $var4\\n" + "type": "if", + "goal": "1 == 1", + "run": [ + { + "type": "parameter", + "printf": "$var3, $var4\\n" + } + ] } - ] - } - ] - }, - { - "type" : "command_call", - "exit": "0" - } - ] - } + ] + }, + { + "type": "command_call", + "exit": "0" + } + ] + } ], - "conditions" : [ + "conditions": [ { - "type" : "if", - "goal" : "1 == 1", - "run" : [ - { - "printf":"$var1, $var2\\n" - } + "type": "if", + "goal": "1 == 1", + "run": [ + { + "type": "parameter", + "printf": "$var1, $var2\\n" + } ] }, { - "type" : "case", - "goal" : "option", - "switch" : [ + "type": "case", + "goal": "option", + "switch": [ { "-h|-help|--help": "help_menu" } ] }, { - "type" : "while", - "goal" : "$i -lt 10", - "run" : [ + "type": "while", + "goal": "$i -lt 10", + "run": [ { - "type" : "parameter", + "type": "parameter", "printf": "loop...\\n" - },{ - "type" : "declare", + }, + { + "type": "declare", "i": "$((i+1))" } ] }, { - "type" : "for", - "goal" : "i=0; $i < 10; i++", - "run" : [ + "type": "for", + "goal": "i=0; $i < 10; i++", + "run": [ { - "type" : "declare", + "type": "declare", "j": "$((j+1))" - },{ - "type" : "parameter", + }, + { + "type": "parameter", "printf": "loop $j\\n" } ]