2016-12-16 33 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'? –