在终端中运行的命令不适用于 go exec.Command

Command that works in terminal doesn't work with go exec.Command

我正在尝试从 go 脚本附加到 go-ethereum 节点:

accountInfo:= fmt.Sprintf("attach %v --exec 'eth.getBalance(eth.accounts[0])'", connect)
    //x, err := exec.Command("geth", accountInfo).Output() // returns 'Fatal: Unable to attach to remote geth: no known transport for URL scheme "c"'
    x, err := exec.Command("geth", accountInfo).Output() // returns "invalid command: "attach ws://127.0.0.1:8101...." <--- rest of the metaData string

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

这个命令在终端中运行得很好,但是当运行这样时它一直告诉我它是无效的。这让我发疯。

来自os/exec documentation

Unlike the "system" library call from C and other languages, the os/exec package intentionally does not invoke the system shell and does not expand any glob patterns or handle other expansions, pipelines, or redirections typically done by shells.

由于 exec.Command()arg ...string 参数没有被 shell 处理,每个参数都完全按照指定的方式传递给命令。在您的情况下,metaData 的全部内容作为单个参数提供给 geth

您应该改为创建一段字符串,每个字符串包含一个参数。然后使用 ... 符号将该切片作为 arg 参数提供。

下面是一个使用 uname 命令进行演示的示例:

package main

import (
    "fmt"
    "os/exec"
)

func main() {
    command := "uname"
    argsString := "--kernel-name --machine"
    argsSlice := []string{"--kernel-name", "--machine"}

    // Equivalent command:
    // $ uname "--kernel-name --machine"
    fmt.Println("exec.Command(command, argsString)")
    stringOutput, err := exec.Command(command, argsString).CombinedOutput()
    if err != nil {
        fmt.Printf("Failed: %s\n", err)
    }
    fmt.Printf("Output:\n%s\n", stringOutput)

    // Equivalent command:
    // $ uname --kernel-name --machine
    fmt.Println("exec.Command(command, argsSlice)")
    sliceOutput, err := exec.Command(command, argsSlice...).CombinedOutput()
    if err != nil {
        fmt.Printf("Failed: %s", err)
    }
    fmt.Printf("Output:\n%s\n", sliceOutput)
}

这是输出:

$ go run main.go
exec.Command(command, argsString)
Failed: exit status 1
Output:
uname: unrecognized option '--kernel-name --machine'
Try 'uname --help' for more information.

exec.Command(command, argsSlice)
Output:
Linux x86_64