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

时间:2018-11-14 08:47:24

标签: go

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

不带引号。

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

3 个答案:

答案 0 :(得分:5)

rm \ file_x.php (和所有其他env变量)由shell扩展。您没有执行Shell,因此它们不会扩展。

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

$HOME

或者这个:

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

请注意,如果commandToRun := os.ExpandEnv("echo $HOME") command := exec.Command(strings.Fields(commandToRun)...) 扩展为包含空格的字符串,则后一种方法将不起作用,因此,在此用例中,$HOME方法通常更安全/更可取。

答案 1 :(得分:3)

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

os.ExpandEnv("echo $HOME")

来自docs

  

ExpandEnv根据当前环境变量的值替换字符串中的$ {var}或$ var。未定义变量的引用将替换为空字符串。

答案 2 :(得分:1)

如果要获取$ 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"))