在go中运行带有参数的字符串命令

eulz3vhy  于 2023-02-06  发布在  Go
关注(0)|答案(3)|浏览(121)

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

没有引号。
这和我想要的差不多,但不完全一样。

1sbrub3j

1sbrub3j1#

$HOME(以及所有其他env变量)是由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方法通常更安全/更适合此用例。

4si2a6ki

4si2a6ki2#

在执行命令之前,可以使用os.ExpandEnv主动展开字符串中的所有env变量:

os.ExpandEnv("echo $HOME")

来自文档:
ExpandEnv根据当前环境变量的值替换字符串中的${var}或$var。对未定义变量的引用被替换为空字符串。

t1rydlwq

t1rydlwq3#

如果要获得$ echo $HOME的输出,最少需要以下代码

fmt.Println(os.Getenv("HOME"))

不需要更多了。

  • 如果使用os.ExpandEnv("echo $HOME"),则首先会展开$HOME var,然后它会提供类似echo /home/<user>的字符串
  • 如果使用command := exec.Command("echo", os.Getenv("HOME")),则它将被解析为command := exec.Command("echo", "/home/<user>"),最后将得到输出/home/<user>
  • 如果您使用

commandToRun := os.ExpandEnv("echo $HOME") command := exec.Command(strings.Fields(commandToRun)...)
那么它将像先前的情况一样被处理。
所以更好的方法是只使用fmt.Println(os.Getenv("HOME"))

相关问题