-1

so my code looks like this , i have a function defined as the following :

func shellOut(command string) (string, string, error) {
    var stdout bytes.Buffer
    var stderr bytes.Buffer
    cmd := exec.Command("bash", "-c", command)
    cmd.Stdout = &stdout
    cmd.Stderr = &stderr
    err := cmd.Run()
    return stdout.String(), stderr.String(), err
}

and a while later i am doing this.

  t := "yoooooooooooo\"oo)(';#oooooooooooo"
    out, stderr, err := shellOut("echo \"" + t + "\"  | ./doOperation.sh")
    if err != nil {
        log.Printf("final error: %v\nstderr: %s", err, stderr)
    }   
    fmt.Println(out)

but i am getting an error that looks like this:

2021/10/14 22:54:18 final error: exit status 1
stderr: bash: -c: line 838: syntax error near unexpected token `('
bash: -c: line 838: `                return "Symbol(" + String(void 0 === t ? "" : t) + ")_" + (++n + r).toString(36)'

and when i give the variable t a value like "yooooo" its gets executed nicely, so how can i pass a variable with any weird character into echo? is there a way to escape all bad character before passing it?

jub0bs
  • 60,866
  • 25
  • 183
  • 186
  • You are executing `bash`, so you must escape whatever value you are passing according to the shell parsing rule. If you know the binary you want, why not execute that directly? – JimB Oct 14 '21 at 21:30
  • 2
    It's doable - but are you sure you want to? Why are you running a `bash` shell to echo an argument that is piped into another program? There are other mechanism for piping input to an executable directly. – colm.anseo Oct 14 '21 at 21:31
  • I suggest to start a process `bash ./doOperation.sh"` and write the string to it's stdin, from Go. Then you don't need the `echo ... |` pipe – hek2mgl Oct 14 '21 at 21:37
  • Different versions of `echo` (or even the same version, with different run- and/or compile-time options) will behave differently when their first argument starts with `-` and/or any arguments contain backslashes. Having your scripts break because an OS update changed how it behaves is not fun (I know this by experience). Avoid it if possible. See [this question](https://stackoverflow.com/questions/51101308/strange-behaviour-for-echo-with-e-flag-passed-to-bash-with-c-flag) (and plenty of others along similar lines). – Gordon Davisson Oct 14 '21 at 21:52
  • I got it working nicely with writing the string to its stdin, thanks to everyone who commented! – hackerdudeeeeee Oct 17 '21 at 16:07

1 Answers1

1

For purely academic purposes, I'm posting this function, as I had to do something similar a while back:

var bashReplacer = strings.NewReplacer(
    `)`, `\)`, // using back-ticks to keep our sanity
    `(`, `\(`,
    `'`, `\'`,
    `"`, `\"`,
    `$`, `\$`, // include if you don't want variable substitutions
    "`", "\\`", // can't use back-ticks to include a back-tick, so back to double-quotes
)

func bashEscape(s string) string { return bashReplacer.Replace(s) }

https://play.golang.org/p/uNfI_2MyjcI

However, as I mentioned in the comments, you can avoid all the pain of shell escaping by just running the target script directly, and feed in your UTF-8 string unaltered like so:

func execWithStdin(command, stdinText string) (string, string, error) {
    var (
        stdout bytes.Buffer
        stderr bytes.Buffer
    )

    cmd := exec.Command(command)
    cmd.Stdin = strings.NewReader(stdinText) // pass in our data via Stdin
    cmd.Stdout = &stdout
    cmd.Stderr = &stderr
    err := cmd.Run()
    return stdout.String(), stderr.String(), err
}

to use:

t := `yoooooooooooo"oo)(';#oooooooooooo`
t += "`" // add a back-tick to make things interesting

// no shell escaping necessary:

out, stderr, err := execWithStdin("./doOperation.sh", t)
colm.anseo
  • 19,337
  • 4
  • 43
  • 52