6

I'm currently trying to execute a simple echo command in Golang on Linux. My code is the following:

cmd = exec.Command("echo", "\"foo 0x50\"", ">", "test.txt")

_, err = cmd.Output()

if err != nil {
    fmt.Println(err)
}

But test.txt doesn't appear in my folder (even after compile and run the code). That not the first that that I use this method to execute commands and I never thought that I will be block on an echo command.

So how can I fix this code in order to have "foo 0x50" (with the quotes) in the test.txt?

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
Majonsi
  • 384
  • 1
  • 4
  • 17

3 Answers3

7

You can redirect the stdout like this:

// Remove the redirect from command
cmd := exec.Command("echo", "\"foo 0x50\"")

// Make test file
testFile, err := os.Create("test.txt")
if err != nil {
    panic(err)
}
defer outfile.Close()

// Redirect the output here (this is the key part)
cmd.Stdout = testFile

err = cmd.Start(); if err != nil {
    panic(err)
}
cmd.Wait()
Tyler
  • 17,669
  • 10
  • 51
  • 89
  • Okay! but why I can't do it on one line like I tried at the beginning ? – Majonsi Oct 17 '16 at 16:04
  • 2
    @Majonsi, sort of yes -- you just have to know that those `>`, `<`, `|` etc are interpreted by your *shell,* and the OS kernel into which `exec.Cmd.Run` shovels the process specification knows nothing about them. So one way to have that "in one line" is to exec `/bin/sh -c "echo blah blah >file.txt"`, so that not `/bin/echo` is spawned but a shell which is then told to execute a specific script. The shell parses out that redirection from the script and arrange for them to happen. – kostix Oct 17 '16 at 16:13
  • 2
    @Majonsi, please note that while that would work, you have to think *thrice* (or more) before treading that route: as soon as you need to encode some data which might contain single or double quotes or redirection symbols or whatnot you enter the quoting hell. Much worse is the situation when you need to pass to the command you're executing some data acquired from the user: you will *have to* protect it properly from being interpreted by the shell, and that means wandering through that quoting hell being chest-deep in it. Better don't, really. – kostix Oct 17 '16 at 16:16
  • @Majonsi, In your particular case, the code by Tyler could have been wrapped into a single function. If you want this stuff be more flexibe, better use a special battle-tested library for this: https://labix.org/pipe – kostix Oct 17 '16 at 16:19
  • Okay! Thanks for the great explanation and solution. Can you post your answer in order to accept it as a solution? – Majonsi Oct 17 '16 at 16:20
  • @Majonsi, thanks. I think this answer is *the* one to be accepted. If its author wishes, they could incorporate my commends into an edit. But I think it's fine as it's stands: comments meant to expand the answer, and so they do here :-) – kostix Oct 17 '16 at 16:22
  • Let me more emphatically reiterate @kostik 's note about quoting. Always ALWAYS use list form/exec() form call outs to external commands and avoid the shell if there's a variable within 50 lines. It's super hard to get right and it's a wellspring of shell injection attacks (very bad ones) if you get it wrong. – BJ Black Oct 18 '16 at 01:05
0

For anyone who wants to pass the complete command in oneline/string ,

func call(command string) {
    cmd := exec.Command("sudo", "bash", "-c", command)
    cmd.Stdin = os.Stdin
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr
    err := cmd.Start()
    if err != nil {
      fmt.Println(err)
    }
    err1 := cmd.Wait()
    if err1 != nil {
      fmt.Println(err1)
    }
 }

The Wait waits for the command to exit and waits for any copying to stdin or copying from stdout or stderr to complete. It closes the pipe after seeing the command exit.

Sources :

https://stackoverflow.com/a/43246464/9892358

https://stackoverflow.com/a/43246464/9892358

https://zetcode.com/golang/exec-command/

0
cmd = exec.Command("/bin/bash", "-c", "echo \"foo 0x50\" > test.txt")

_, err = cmd.Output()

if err != nil {
    fmt.Println(err)
}
Anders
  • 1
  • 1
    Thank you for contributing to the Stack Overflow community. This may be a correct answer, but it’d be really useful to provide additional explanation of your code so developers can understand your reasoning. This is especially useful for new developers who aren’t as familiar with the syntax or struggling to understand the concepts. **Would you kindly [edit] your answer to include additional details for the benefit of the community?** – Jeremy Caney Aug 09 '23 at 01:42