2015-05-01 32 views
2

我想用Go來源代碼。理想的下面的代碼如何使用Go提供一個shell腳本?

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

但是,我知道「源」是一個bash內置函數,而不是一個可執行文件。

不過,我已經找到了一些方法來模擬在Python這種行爲:

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

不幸的是,我不知道如何在Go翻譯這個。有人有想法嗎?

謝謝!

+2

你不行。 「採購」只能在shell進程中進行。 –

+0

順便說一句,*請*不要在「真實」的代碼中做這樣的事情。至少不是沒有*巨大的警告*。 Shell腳本當然可以有任意的副作用,我想不出用shell腳本來做到這一點的簡單安全的方法,但是有一些簡單的安全選擇,幾乎覆蓋了我能想到的所有用例。 –

+0

感謝您的警告和關注。我應該解釋我想要做什麼。我試圖用Go程序初始化我的shell。所以我必須複製/鏈接一些點文件並從其他源文件中獲取。這就是爲什麼副作用在我的情況下預計。 – Pith

回答

4

您可以運行使用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")) 
+0

您的示例適用於更新運行命令的環境,但不會影響Go程序的當前執行上下文。請參閱:http://beta.42grounds.io/s/7fa5ab8ec1b1e57d5b13ca9b71f3b4e1b107da4b11be01fb87c74893e12b2508 – Pith

+0

@Pith,使用play.golang.org鏈接到Go代碼,您的鏈接是完全不可讀的。例如。 https://play.golang.org/p/asAcntp-j8 –

+1

我不明白你爲什麼發現它不可讀。但是爲什麼我沒有使用Go操場,是因爲劇本沒有在Go操場上運行。不像我發佈的在容器中運行腳本的鏈接。 – Pith

0

我最近增加這樣的實用功能,我的殼/ 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,因此如果您想要防止永久循環或其他錯誤代碼被保護,您可以設置超時。