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

huangapple go评论73阅读模式
英文:

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

问题

我正在尝试使用golang在浏览器中打开给定的URL。当我使用这段代码时,它按预期工作,并在浏览器中打开给定的URL:

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())
	}
}

输出结果(打开浏览器):

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

但是,当我将exec.Command("echo", "https://google.com")的输出作为第二个exec.Command调用的参数时,程序返回以下错误:

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())
	}
}

输出结果(错误中包含当前目录路径作为URL的一部分):

~/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.

在第二个代码块中,我做错了什么?

英文:

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
)

答案1

得分: 2

如@JimB所指出,命令输出的末尾隐含了一个换行符。

使用fmt%q动词是一个好的做法,可以确保输出没有不明字符:

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

因此,可以通过在源代码中使用echo -n来消除换行符来修复这个问题:

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

或者在接收端进行修复:

url = strings.TrimSpace(url)
英文:

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)

huangapple
  • 本文由 发表于 2021年8月29日 05:50:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/68968352.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定