猿问

从带有参数的字符串运行命令

我正在尝试使用 go 运行命令。命令在一个字符串中。


package main


import (

    "log"

    "os"

    "os/exec"

    "strings"


    "github.com/davecgh/go-spew/spew"

)


func main() {

    commandToRun := `echo $HOME`


    log.Printf("Running %s\n", commandToRun)


    args := strings.Fields(commandToRun)

    spew.Dump(args[1:len(args)])

    command := exec.Command(args[0], args[1:len(args)]...)

    command.Stdout = os.Stdout

    command.Stdin = os.Stdin

    command.Stderr = os.Stderr

    err := command.Run()


    if err != nil {

        log.Printf("Command finished with error: %v", err)

    }

}

输出是:


2018/11/14 09:41:22 Running echo $HOME

([]string) (len=1 cap=1) {

 (string) (len=5) "$HOME"

}

$HOME

我想要的是:


2018/11/14 09:41:22 Running echo $HOME

([]string) (len=1 cap=1) {

 (string) (len=5) "$HOME"

}

/home/whatever

看起来 go 正在以某种方式清理字符串。所以$HOME没有展开。有什么方法可以像在 shell 中输入一样运行字符串吗?


这是重要的部分。理想情况下,我想在当前 shell 中从字符串转为类型。


编辑:下面的例子解决了最简单的场景,但没有涵盖“运行字符串就好像它被输入到 shell 中一样”部分。


如果我切换到expandenv:


commandToRun := os.ExpandEnv(`echo "$HOME"`)

我得到:


2018/11/14 11:45:44 Running echo "/Users/rafael"

([]string) (len=1 cap=1) {

 (string) (len=15) "\"/home/whatever\""

}

"/home/whatever"

我在 shell 中得到的是:


$ > echo "$HOME"

/home/whatever

没有引号。


这接近我想要的,但不完全是。


摇曳的蔷薇
浏览 112回答 4
4回答

沧海一幻觉

$HOME(以及所有其他环境变量)由 shell 扩展。您没有执行 shell,因此它们不会扩展。您需要直接在 go 中查找 env 变量,例如:command := exec.Command("echo", os.Getenv("HOME"))或这个:commandToRun := os.ExpandEnv("echo $HOME")args := strings.Fields(commandToRun)command := exec.Command(args[0], args[1:]...)$HOME请注意,如果扩展为包含空格的字符串,最后一种方法将不起作用,因此该os.Getenv方法通常更安全/更适合此用例。

PIPIONE

在执行命令之前,您可以使用以下方式主动扩展字符串中的所有环境变量os.ExpandEnv:os.ExpandEnv("echo $HOME")从文档:ExpandEnv 根据当前环境变量的值替换字符串中的${var} 或$var。对未定义变量的引用将替换为空字符串。

明月笑刀无情

如果您想获得 的输出$ echo $HOME,您需要的最少代码是fmt.Println(os.Getenv("HOME"))不需要更多了。如果你使用os.ExpandEnv("echo $HOME"),那么首先$HOMEvar 将被扩展然后它会给你一个像这样的字符串echo /home/<user>如果您使用command := exec.Command("echo", os.Getenv("HOME")), 那么它将被解析为command := exec.Command("echo", "/home/<user>")finally 这将给出输出/home/<user>如果你使用commandToRun := os.ExpandEnv("echo $HOME") command := exec.Command(strings.Fields(commandToRun)...)那么它将像以前的案例一样处理。所以更好的方法是只使用fmt.Println(os.Getenv("HOME")).

ITMISS

您需要运行一个 shell。在 Go 中扩展它似乎很愚蠢并且容易出错,因为你有一个可以运行的 shell。commandToRun&nbsp;:=&nbsp;`echo&nbsp;"$SHELL"` cmd&nbsp;:=&nbsp;exec.Command("/bin/sh",&nbsp;"-c",&nbsp;commandToRun) command&nbsp;:=&nbsp;exec.Command(args[0],&nbsp;args[1:len(args)]...) command.Stdout&nbsp;=&nbsp;os.Stdout command.Stdin&nbsp;=&nbsp;os.Stdin command.Stderr&nbsp;=&nbsp;os.Stderr err&nbsp;:=&nbsp;command.Run()这应该适用于任何 POSIX 系统。今天的孩子们在他们的命令行中加入了很多 bashisms,因此您可以将其切换为运行,/bin/bash但请注意,这在 FreeBSD 或其他一些系统(其他 BSD 及其派生系统)上不起作用。
随时随地看视频慕课网APP

相关分类

Go
我要回答