2016-12-16 84 views
1

我的Go應用程序輸出一定數量的文本數據,我需要將其傳送到某個外部命令(例如less)。我沒有找到任何方法將這些數據傳送到syscall.Exec'ed過程。管道執行過程

作爲一種變通方法我是文本數據寫入到一個臨時文件,然後使用該文件作爲參數傳遞給less

package main 

import (
    "io/ioutil" 
    "log" 
    "os" 
    "os/exec" 
    "syscall" 
) 

func main() { 
    content := []byte("temporary file's content") 
    tmpfile, err := ioutil.TempFile("", "example") 
    if err != nil { 
     log.Fatal(err) 
    } 

    defer os.Remove(tmpfile.Name()) // Never going to happen! 

    if _, err := tmpfile.Write(content); err != nil { 
     log.Fatal(err) 
    } 
    if err := tmpfile.Close(); err != nil { 
     log.Fatal(err) 
    } 

    binary, err := exec.LookPath("less") 
    if err != nil { 
     log.Fatal(err) 
    } 

    args := []string{"less", tmpfile.Name()} 

    if err := syscall.Exec(binary, args, os.Environ()); err != nil { 
     log.Fatal(err) 
    } 
} 

它的工作原理,但留下一個文件系統上的臨時文件,因爲syscall.Exec替換當前與另一個(less)一個進程和延遲os.Remove將不會運行。這種行爲是不可取的。

有什麼辦法可以將某些數據傳輸到外部進程而不會留下任何僞像?

回答

2

您應該使用os/exec構建一個exec.Cmd執行,然後您可以提供任何io.Reader作爲該命令的標準輸入。

從文檔中的例子:

cmd := exec.Command("tr", "a-z", "A-Z") 
cmd.Stdin = strings.NewReader("some input") 
var out bytes.Buffer 
cmd.Stdout = &out 
err := cmd.Run() 
if err != nil { 
    log.Fatal(err) 
} 
fmt.Printf("in all caps: %q\n", out.String()) 

如果你想直接寫命令的標準輸入,然後調用cmd.StdInPipe得到一個io.WriteCloser你可以寫信給。

如果您真的需要exec這個過程來替代當前的過程,您可以在執行前簡單地刪除該文件,然後將該文件描述符作爲程序的標準輸入提供。

content := []byte("temporary file's content") 
tmpfile, err := ioutil.TempFile("", "example") 
if err != nil { 
    log.Fatal(err) 
} 
os.Remove(tmpfile.Name()) 

if _, err := tmpfile.Write(content); err != nil { 
    log.Fatal(err) 
} 

tmpfile.Seek(0, 0) 

err = syscall.Dup2(int(tmpfile.Fd()), syscall.Stdin) 
if err != nil { 
    log.Fatal(err) 
} 

binary, err := exec.LookPath("less") 
if err != nil { 
    log.Fatal(err) 
} 

args := []string{"less"} 

if err := syscall.Exec(binary, args, os.Environ()); err != nil { 
    log.Fatal(err) 
} 
+0

謝謝,我知道'os/exec' * et al *,但它不會解決我的問題。我想將數據通過管道傳輸到類似頁面的環境('less'),而不是使用一些文本工具處理它並處理輸出。 –

+0

@PetrShevtsov:我誤解了,因爲你不能直接管道到你要執行的過程。管道阻塞並且數據必須在某處緩衝。每個人都說這不是一個Go問題,因爲你不能一般這樣做。如果你在一個posix系統上(我用syscall.Exec和'less'調用假設),你可以刪除tmp文件。 – JimB

+0

謝謝,它的作品!但我可以擺脫臨時文件,並直接寫入'syscall.Stdin'? –