how can I get stdin to exec cmd in golang

后端 未结 4 1005
故里飘歌
故里飘歌 2021-02-07 06:32

I have this code

subProcess := exec.Cmd{
    Path: execAble,
    Args: []string{
        fmt.Sprintf(\"-config=%s\", *configPath),
        fmt.Sprintf(\"-serverT         


        
相关标签:
4条回答
  • 2021-02-07 06:51

    While you cannot directly do this as @AlexKey wrote earlier still you can make some workarounds. If os prevents you to pipe your own standard streams who cares all you need 2 channels and 2 goroutines

    var stdinChan chan []byte
    var stdoutChan chan []byte
    
    //when something happens in stdout of your code just pipe it to stdout chan
    stdoutChan<-somehowGotDataFromStdOut
    

    then you need two funcs as i mentioned before

    func Pipein(){
        for {
            stdinFromProg.Write(<-stdInChan)
        }
    }
    

    The same idea for the stdout

    0 讨论(0)
  • 2021-02-07 06:59

    I made a simple program (for testing). It reads a number and writes the given number out.

    package main
    
    import (
        "fmt"
    )
    
    func main() {
        fmt.Println("Hello, What's your favorite number?")
        var i int
        fmt.Scanf("%d\n", &i)
        fmt.Println("Ah I like ", i, " too.")
    }
    

    And here is the modified code

    package main
    
    import (
        "fmt"
        "io"
        "os"
        "os/exec"
    )
    
    func main() {
        subProcess := exec.Command("go", "run", "./helper/main.go") //Just for testing, replace with your subProcess
    
        stdin, err := subProcess.StdinPipe()
        if err != nil {
            fmt.Println(err) //replace with logger, or anything you want
        }
        defer stdin.Close() // the doc says subProcess.Wait will close it, but I'm not sure, so I kept this line
    
        subProcess.Stdout = os.Stdout
        subProcess.Stderr = os.Stderr
    
        fmt.Println("START") //for debug
        if err = subProcess.Start(); err != nil { //Use start, not run
            fmt.Println("An error occured: ", err) //replace with logger, or anything you want
        }
    
        io.WriteString(stdin, "4\n")
        subProcess.Wait()
        fmt.Println("END") //for debug
    }
    

    You interested about these lines

    stdin, err := subProcess.StdinPipe()
    if err != nil {
        fmt.Println(err)
    }
    defer stdin.Close()
    //...
    io.WriteString(stdin, "4\n")
    //...
    subProcess.Wait()
    

    Explanation of the above lines

    1. We gain the subprocess' stdin, now we can write to it
    2. We use our power and we write a number
    3. We wait for our subprocess to complete

    Output

    START
    Hello, What's your favorite number?
    Ah I like 4 too.
    END

    For better understanding

    0 讨论(0)
  • 2021-02-07 07:02

    There's now an updated example available in the Go docs: https://golang.org/pkg/os/exec/#Cmd.StdinPipe

    If the subprocess doesn't continue before the stdin is closed, the io.WriteString() call needs to be wrapped inside an anonymous function:

    func main() {
        cmd := exec.Command("cat")
        stdin, err := cmd.StdinPipe()
        if err != nil {
            log.Fatal(err)
        }
    
        go func() {
            defer stdin.Close()
            io.WriteString(stdin, "values written to stdin are passed to cmd's standard input")
        }()
    
        out, err := cmd.CombinedOutput()
        if err != nil {
            log.Fatal(err)
        }
    
        fmt.Printf("%s\n", out)
    }
    
    0 讨论(0)
  • 2021-02-07 07:11

    Though this question is a little old, but here is my answer:

    This question is of course very platform specific as how standard IO is handled depends on the OS implementation and not on Go language. However, as general rule of thumb (due to some OSes being prevailing), "what you ask is not possible".

    On most of modern operating systems you can pipe standard streams (as in @mraron's answer), you can detach them (this is how daemons work), but you cannot reassign or delegate them to another process.

    I think this limitation is more because of security concern. There are still from time to time bugs being discovered that allow remote code execution, imagine if OS was allowing to reassign/delegate STDIN/OUT, then with such vulnerabilities the consequences would be disastrous.

    0 讨论(0)
提交回复
热议问题