我正在尝试使用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
不带引号。
这接近于我想要的,但不完全是它。
答案 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"))
。