Bridge Dudley
Bridge Dudley

Reputation: 299

golang exec command: stream output to stdout *and* capture output in variable

I'm building a cli in go and have the following situation. I'm calling a bash command from go that prompts the user for a login, then prints a token after login. For example:

cmd := exec.Command("vault", "login", "-method=okta", "-format=json", "username=abc")
cmd.Stdin = os.Stdinout
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
_ = cmd.Run()

This streams the output nicely, but I have no way to parse the token from the command's output after the user logs in. I've tried to wrap the cmd.Run() into piping functions like this this and this but in both cases the output returned is empty. Any ideas?

Thanks!

Upvotes: 7

Views: 8859

Answers (2)

Don't make your structure for nothing. Use bytes.Buffer

package main

import (
    "bytes"
    "log"
)

func main() {
    var buffer bytes.Buffer
    cmd := exec.Command("vault", "login", "-method=okta", "-format=json", "username=abc")
    cmd.Stdout = &buffer
    _ = cmd.Run()
    log.Printf("Vault login output: %s", buffer.String())
}

Upvotes: 5

Suzu Hirose
Suzu Hirose

Reputation: 312

There are probably lots of packages to do this, but it's not hard to whip up your own:

package main

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

type saveOutput struct {
    savedOutput []byte
}

func (so *saveOutput) Write(p []byte) (n int, err error) {
    so.savedOutput = append(so.savedOutput, p...)
    return os.Stdout.Write(p)
}

func main() {
    var so saveOutput
    cmd := exec.Command("factor", "999999")
    cmd.Stdin = os.Stdin
    cmd.Stdout = &so
    cmd.Stderr = os.Stderr
    _ = cmd.Run()
    fmt.Printf("I got this output: %s\n", so.savedOutput)
}

Playground: https://go.dev/play/p/T-o3QvGOm5q

Upvotes: 9

Related Questions