diff --git a/internal/pkg/bifs/system.go b/internal/pkg/bifs/system.go index 974325b8e4..af95695dac 100644 --- a/internal/pkg/bifs/system.go +++ b/internal/pkg/bifs/system.go @@ -44,3 +44,61 @@ func BIF_system(input1 *mlrval.Mlrval) *mlrval.Mlrval { return mlrval.FromString(outputString) } + +func BIF_exec(mlrvals []*mlrval.Mlrval) *mlrval.Mlrval { + + if len(mlrvals) == 0 { + return mlrval.ERROR + } + + cmd := exec.Command(mlrvals[0].AcquireStringValue()) + combinedOutput := false + + args := []string { mlrvals[0].AcquireStringValue() } + if len(mlrvals) > 1 { + for _, val := range mlrvals[1].GetArray()[0:] { + args = append(args, val.AcquireStringValue()) + } + } + cmd.Args = args + + if len(mlrvals) > 2 { + + for pe := mlrvals[2].AcquireMapValue().Head; pe != nil; pe = pe.Next { + if pe.Key == "env" { + env := []string {} + for _, val := range pe.Value.GetArray()[0:] { + env = append(env, val.AcquireStringValue()) + } + cmd.Env = env + } + if pe.Key == "dir" { + cmd.Dir = pe.Value.AcquireStringValue() + } + if pe.Key == "combined_output" { + combinedOutput = pe.Value.AcquireBoolValue() + } + + if pe.Key == "stdin_string" { + cmd.Stdin = strings.NewReader(pe.Value.AcquireStringValue()) + } + } + + } + + outputBytes := []byte(nil) + err := error(nil) + + if combinedOutput { + outputBytes, err = cmd.CombinedOutput() + } else { + outputBytes, err = cmd.Output() + } + + if err != nil { + return mlrval.ERROR + } + + outputString := strings.TrimRight(string(outputBytes), "\n") + return mlrval.FromString(outputString) +} diff --git a/internal/pkg/dsl/cst/builtin_function_manager.go b/internal/pkg/dsl/cst/builtin_function_manager.go index e23012ac9e..02920eefcf 100644 --- a/internal/pkg/dsl/cst/builtin_function_manager.go +++ b/internal/pkg/dsl/cst/builtin_function_manager.go @@ -1923,6 +1923,24 @@ either case it should return a boolean.`, unaryFunc: bifs.BIF_system, }, + { + name: "exec", + class: FUNC_CLASS_SYSTEM, + help: `'$output = exec( + "command", + ["arg1", "arg2"], + {"env": ["ENV_VAR=ENV_VALUE"], + "dir": "/tmp/run_command_here", + "stdin_string": "this is input fed to program", + "combined_output": true +)' +Run a command via executable, path, args and environment, yielding its stdout minus final carriage return.`, + examples: []string{ + `exec("echo", ["Hello", "$YOUR_NAME"], {"env": "YOUR_NAME=World"}) outputs "Hello World"`, + }, + variadicFunc: bifs.BIF_exec, + }, + { name: "version", class: FUNC_CLASS_SYSTEM,