Search code examples
goexec

Why does os/exec command not work as expected when passed argument is the output of previously run exec?


I'm trying to open the given URL on the browser using golang. When I use this code, it works as expected and opens the given URL in the browser:

func main() {
    url := "https://google.com"

    fmt.Printf(url)

    cmd := exec.Command("open", url)

    var out bytes.Buffer
    var stderr bytes.Buffer
    cmd.Stdout = &out
    cmd.Stderr = &stderr

    err := cmd.Run()
    
    if err != nil {
        fmt.Println(fmt.Sprint(err) + ": " + stderr.String())
    }
}

outputs (opens the browser):

~/workspace/go/so ❯ go run main.go
https://google.com%

But when I use the output of exec.Command("echo", "https://google.com") as the argument of the second exec.Command call then program returns an error as below:

func main() {
    output, err := exec.Command("echo", "https://google.com").Output()

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

    url := string(output)

    fmt.Printf(url)

    cmd := exec.Command("open", url)

    var out bytes.Buffer
    var stderr bytes.Buffer
    cmd.Stdout = &out
    cmd.Stderr = &stderr

    err = cmd.Run()
    
    if err != nil {
        fmt.Println(fmt.Sprint(err) + ": " + stderr.String())
    }
}

output (there is current directory path as a behind URL in the error):

~/workspace/go/so ❯ go run main.go
https://google.com
exit status 1: The file /Users/kadir/workspace/go/so/https:/google.com
 does not exist.

What am I doing wrong in the second code block?


my go version is 1.17 and go.mod file is this:

module so

go 1.17

require github.com/urfave/cli/v2 v2.3.0

require (
    github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
    github.com/russross/blackfriday/v2 v2.1.0 // indirect
    github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
)

Solution

  • As @JimB noted there's an implicitly newline at the end of the command output.

    It's a good practice to use the fmt %q verb to ensure output does not have rogue characters:

     fmt.Printf("%q\n", url)  // "https://google.com\n"
    

    So fix this either at the source, using echo -n to suppress the newline:

    output, err := exec.Command("echo", "-n", "https://google.com").Output()
    

    or on the receiving end:

    url = strings.TrimSpace(url)