在程序化Shell命令执行中嵌入环境变量

时间:2019-03-09 00:22:40

标签: bash shell go

我处于一种试图执行shell命令的情况,但是其参数必须正确解释为环境变量。

例如,当我在终端中输入以下内容

ls $GOPATH

Bash解释并扩展变量$GOPATH,并列出$GOPATH目录的内容。我正在尝试对Golang的程序化Shell执行类似的操作。

我有以下代码。

package main

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

func main() {
    cmd := exec.Command("echo", "$TESTVAR")

    cmd.Env = append(os.Environ(),
        "TESTVAR=this_is_a_test",
    )

    var outBuff bytes.Buffer
    var errBuff bytes.Buffer

    cmd.Stdout = &outBuff
    cmd.Stderr = &errBuff

    if err := cmd.Run(); err != nil {
        log.Fatal(err)
    }

    fmt.Println(outBuff.String()) // empty
    fmt.Println(errBuff.String()) // empty
}

该程序输出

$ go run test.go
$TESTVAR

有人知道如何使exec库将$ TESTVAR解释为环境变量而不是字符串文字吗?预先感谢!

2 个答案:

答案 0 :(得分:2)

替换

cmd := exec.Command("echo", "$TESTVAR")

使用

cmd := exec.Command("sh", "-c", "echo $TESTVAR")

答案 1 :(得分:1)

Bash和其他shell解释和扩展变量,但是应用程序未执行Bash。

应用程序正在执行echo命令。与大多数其他命令一样,echo命令不会在其参数中扩展环境变量。

您可以运行Bash(如另一个答案所示),也可以自行扩展环境变量。使用os.Expand函数执行此操作的方法如下:

func newCommandEnv(env []string, cmd string, args ...string) *exec.Cmd {
    m := map[string]string{}
    for _, e := range env {
        if i := strings.Index(e, "="); i >= 0 {
            m[e[:i]] = e[i+1:]
        }
    }
    fn := func(placeholder string) string {
        return m[placeholder]
    }
    for i, a := range args {
        args[i] = os.Expand(a, fn)
    }
    fmt.Println(args)
    c := exec.Command(cmd, args...)
    c.Env = env
    return c
}