0

I'm running a really simple bash script which just echo's some data within Go. I've placed this into a wrapper and used the exec package to execute this. This works nicely by outputting to my terminal, however, I can't find any way to actually store this into a variable in Go.

I'm new to Go, so my debugging skills aren't amazing. However, I've placed some basic logging outputs to try to narrow down where exactly I need to get the output from, but to no avail.

The two functions which run bash:

func main(){
    _, result,_ := runBash()
    log.Printf("Result: ", result)
}


func runBash()(bool, string, string){
    cmd := exec.Command("/bin/sh", "-s")
    cmd.Stdin = strings.NewReader(replicateRouter())
    return finishRunning(cmd)
}

func finishRunning(cmd *exec.Cmd) (bool, string, string) {
    log.Printf("Running: ")
    stdout, stderr := bytes.NewBuffer(nil), bytes.NewBuffer(nil)
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr
    done := make(chan struct{})
    defer close(done)
    go func() {
        for {
            select {
            case <-done:
                return
            case s := <-signals:
                cmd.Process.Signal(s)
            }
        }
    }()
    log.Printf("Flag 1")
    if err := cmd.Run(); err != nil {
        log.Printf("Error running %v", err)
        return false, string(stdout.Bytes()), string(stderr.Bytes())
    }
    log.Printf("Flag 2")
    return true, string(stdout.Bytes()), ""
}

This is the function to fake test my bash script:

func replicateRouter() string{
    return `echo <HOSTNAME> <IP> <MACADDRESS>`
}

The echo happens between flag 1 & 2 and at any point when I try to log any values from cmd/stdout I get empty strings. Within the main function, the result variable produces: 2020/06/19 18:17:14 Result: %!(EXTRA string=)

So I suppose my first question is why isn't result (which is in theory string(stdout.Bytes())) not producing the echo? & Secondly, where/how can I save the output to a variable?

Thanks & feel free to ping me if I've missed any questions &/or need more details

--Edit: Also forgot to mention, the code was heavily inspired by this Kubernetes go script. If there are any recommendations/criticism to doing it this way, I'd be really happy to hear/learn :)

2
  • Typo? Use stderr and stdout instead of os.Stderr and os.Stdin. Commented Jun 19, 2020 at 18:11
  • Yeah that's right. As soon as I removed os.Stderr/&Stdin and replaced them it worked straight away. I thought using os.stderr/in was how to actually print it to the terminal without using logging/fmt in Go. But we learn something new everyday :) Commented Jun 19, 2020 at 18:22

1 Answer 1

1

Question 1:

stdout and stderr are never assigned to cmd in your code.

try this:

cmd.Stdout = stdout
cmd.Stderr = stderr

alternatively, try this simpler version:

  func main() {
      out, err := exec.Command("date").Output()
      if err != nil {
          log.Fatal(err)
      }
      fmt.Printf("The date is %s\n", out)
  }

Finally, you can "proxy" to os.Stdout

package main

import (
    "bytes"
    "fmt"
    "os/exec"
    "io"
    "os"
)


func main() {
    stdout := new(bytes.Buffer)
    stderr := new(bytes.Buffer)
    _, _ = io.Copy(os.Stdout, stdout)
    _, _ = io.Copy(os.Stderr, stderr)

    cmd  := exec.Command("date")
    cmd.Stdout = stdout
    cmd.Stderr = stderr
    cmd.Run()



    output := string(stdout.Bytes())
    fmt.Printf("The date is %s\n", output)
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks so much, you were right I forgot to assign stdout & stderr anywhere in my code. Now that I did, I was able to place that succesfully into Result. I'll give a try the alternative method. Again thanks, this was killing me!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.