How can I source a shell script using Go?

huangapple go评论89阅读模式
英文:

How can I source a shell script using Go?

问题

我想使用Go语言来源码shell脚本。理想情况下,使用以下代码:

cmd := exec.Command("/bin/bash", "source", file.Name())

但是,我知道"source"是一个bash内置函数,而不是一个可执行文件。

然而,我在Python中找到了一些模拟这种行为的方法:

http://pythonwise.blogspot.fr/2010/04/sourcing-shell-script.html

不幸的是,我不知道如何在Go语言中实现这个。有人有主意吗?

谢谢!

英文:

I want to source shell scripts using Go. Ideally the following code

cmd := exec.Command("/bin/bash", "source", file.Name())

but, I know that "source" is a bash built-in function, not an executable.

However, I have found some ways to mimic this behavior in Python:

http://pythonwise.blogspot.fr/2010/04/sourcing-shell-script.html

Unfortunately, I don't know how to translate this in Go. Does anyone have an idea ?

Thanks !

答案1

得分: 9

在运行程序时,可以使用exec设置环境变量:

cmd := exec.Command("whatever")
cmd.Env = []string{"A=B"}
cmd.Run()

如果你真的需要源代码,可以通过bash运行命令:

cmd := exec.Command("bash", "-c", "source " + file.Name() + " ; echo 'hi'")
cmd.Run()

可以使用这个库进行更全面的工作流程:https://github.com/progrium/go-basher。

更新:这里有一个修改当前环境的示例:

package main

import (
	"bufio"
	"bytes"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"strings"
)

func main() {
	err := ioutil.WriteFile("example_source", []byte("export FOO=bar; echo $FOO"), 0777)
	if err != nil {
		log.Fatal(err)
	}

	cmd := exec.Command("bash", "-c", "source example_source ; echo '<<<ENVIRONMENT>>>' ; env")
	bs, err := cmd.CombinedOutput()
	if err != nil {
		log.Fatalln(err)
	}
	s := bufio.NewScanner(bytes.NewReader(bs))
	start := false
	for s.Scan() {
		if s.Text() == "<<<ENVIRONMENT>>>" {
			start = true
		} else if start {
			kv := strings.SplitN(s.Text(), "=", 2)
			if len(kv) == 2 {
				os.Setenv(kv[0], kv[1])
			}
		}
	}
}

log.Println(os.Getenv("FOO"))
英文:

You can set environmental variables when running a program using exec:

cmd := exec.Command(&quot;whatever&quot;)
cmd.Env = []string{&quot;A=B&quot;}
cmd.Run()

If you really need source then you can run your command through bash:

cmd := exec.Command(&quot;bash&quot;, &quot;-c&quot;, &quot;source &quot; + file.Name() + &quot; ; echo &#39;hi&#39;&quot;)
cmd.Run()

Check out this library for a more full-featured workflow: https://github.com/progrium/go-basher.

Update: Here's an example that modifies the current environment:

package main

import (
	&quot;bufio&quot;
	&quot;bytes&quot;
	&quot;io/ioutil&quot;
	&quot;log&quot;
	&quot;os&quot;
	&quot;os/exec&quot;
	&quot;strings&quot;
)

func main() {
	err := ioutil.WriteFile(&quot;example_source&quot;, []byte(&quot;export FOO=bar; echo $FOO&quot;), 0777)
	if err != nil {
		log.Fatal(err)
	}

	cmd := exec.Command(&quot;bash&quot;, &quot;-c&quot;, &quot;source example_source ; echo &#39;&lt;&lt;&lt;ENVIRONMENT&gt;&gt;&gt;&#39; ; env&quot;)
	bs, err := cmd.CombinedOutput()
	if err != nil {
		log.Fatalln(err)
	}
	s := bufio.NewScanner(bytes.NewReader(bs))
	start := false
	for s.Scan() {
		if s.Text() == &quot;&lt;&lt;&lt;ENVIRONMENT&gt;&gt;&gt;&quot; {
			start = true
		} else if start {
			kv := strings.SplitN(s.Text(), &quot;=&quot;, 2)
			if len(kv) == 2 {
				os.Setenv(kv[0], kv[1])
			}
		}
	}
}

log.Println(os.Getenv(&quot;FOO&quot;))

答案2

得分: 3

我最近在我的shell/bash Golang库中添加了一个这样的实用函数:

https://godoc.org/mvdan.cc/sh/shell#SourceFile

例如,你可以这样做:

vars, err := shell.SourceFile("foo.sh")
if err != nil { ... }
fmt.Println(vars["URL"].Value)
// http://the.url/value

这个函数相当安全,因为它实际上不会调用bash或任何其他程序。它会解析shell脚本,然后解释执行。但在解释执行时,它有一个白名单,规定了脚本可以打开哪些文件和执行哪些程序。

解释器还有一个context.Context,所以如果你想要防止无限循环或其他糟糕的代码,你可以设置一个超时时间。

英文:

I have recently added such a utility function to my shell/bash Golang library:

https://godoc.org/mvdan.cc/sh/shell#SourceFile

For example, you could do:

vars, err := shell.SourceFile(&quot;foo.sh&quot;)
if err != nil { ... }
fmt.Println(vars[&quot;URL&quot;].Value)
// http://the.url/value

It's decently safe, because it never actually calls bash nor any other program. It parses the shell script, then interprets it. But when interpreting, it has a whitelist of what files the script can open and what programs the script can execute.

The interpreter also has a context.Context, so you can set a timeout if you want to be protected against forever loops or other bad code.

huangapple
  • 本文由 发表于 2015年5月2日 05:57:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/29995741.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定