首页 > 解决方案 > 从带有参数的字符串运行命令

问题描述

我正在尝试使用 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"

我在外壳中得到的是:

$ > echo "$HOME"
/home/whatever

没有引号。

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

标签: go

解决方案


$HOME(以及所有其他环境变量)由 shell 扩展。您没有执行外壳程序,因此它们不会被扩展。

您需要直接在 go 中查找 env 变量,例如:

command := exec.Command("echo", os.Getenv("HOME"))

或这个:

commandToRun := os.ExpandEnv("echo $HOME")
command := exec.Command(strings.Fields(commandToRun)...)

$HOME请注意,如果扩展为包含空格的字符串,则最后一种方法将不起作用,因此os.Getenv对于此用例,该方法通常更安全/首选。


推荐阅读