You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go语言中如何将运行命令的stdout传入其stdin?

问题:将运行中程序的stdout内容回传给其stdin

需要实现的逻辑是:捕获一个运行中程序的标准输出内容,将该内容作为输入传入该程序的标准输入,同时获取程序的最终输出结果。

以下是用于演示需求的目标程序:

package main

import (
    "bufio"
    "fmt"
    "math/rand"
    "os"
    "time"
)

func main() {
    rand.Seed(time.Now().Unix())
    var greetings []string = []string{"hi", "hola", "bonjour", "hallo", "whats up"}
    var greeting string = greetings[rand.Intn(len(greetings))]
    fmt.Println(greeting)

    reader := bufio.NewReader(os.Stdin)
    message, _ := reader.ReadString('\n')
    if message == greeting+"\n" {
        fmt.Println("nice to meet you!")
    } else {
        fmt.Println("oops!")
    }
}

该程序会随机输出一句问候语,随后等待标准输入;若输入与问候语一致则输出nice to meet you!,否则输出oops!。

尝试使用StdinPipe和StdoutPipe实现时,程序出现冻结情况,核心问题在于需要先获取stdout内容再关闭stdin,但原代码中的io.ReadAll(stdout)会持续等待stdout关闭,而子程序在输出问候语后会阻塞等待stdin输入,不会主动关闭stdout,导致goroutine一直阻塞。以下是尝试的代码:

package main

import (
    "io"
    "os/exec"
)

func main() {
    cmd := exec.Command("./executable_program")
    stdout, _ := cmd.StdoutPipe()
    stdin, _ := cmd.StdinPipe()

    var c chan []byte = make(chan []byte)

    cmd.Start()
    go func() {
        b, _ := io.ReadAll(stdout)
        c <- b
    }()

    stdin.Write(<-c)
    stdin.Close()

    cmd.Wait()
}

解决方案

问题根源是io.ReadAll会等待整个stdout流关闭才返回,而子程序在输出问候语后并未关闭stdout,而是等待输入。正确的做法是逐行读取stdout的第一行内容,因为目标程序输出问候语后会换行,用bufio.Scanner可以精准捕获这一行内容,无需等待流关闭。

修改后的代码如下:

package main

import (
    "bufio"
    "fmt"
    "os/exec"
    "strings"
)

func main() {
    cmd := exec.Command("./executable_program")
    
    // 创建stdout和stdin管道
    stdout, err := cmd.StdoutPipe()
    if err != nil {
        panic(err)
    }
    stdin, err := cmd.StdinPipe()
    if err != nil {
        panic(err)
    }
    defer stdin.Close()

    // 启动子程序
    if err := cmd.Start(); err != nil {
        panic(err)
    }

    // 用Scanner读取stdout的第一行问候语
    scanner := bufio.NewScanner(stdout)
    var greeting string
    if scanner.Scan() {
        greeting = scanner.Text()
    }
    if err := scanner.Err(); err != nil {
        panic(err)
    }

    // 将问候语写入stdin,注意添加换行符(子程序用ReadString('\n')读取)
    _, err = fmt.Fprintf(stdin, "%s\n", greeting)
    if err != nil {
        panic(err)
    }
    stdin.Close() // 关闭stdin,让子程序继续执行

    // 等待子程序完成,并捕获最终输出
    var output strings.Builder
    scanner = bufio.NewScanner(stdout)
    for scanner.Scan() {
        output.WriteString(scanner.Text() + "\n")
    }
    if err := cmd.Wait(); err != nil {
        panic(err)
    }

    // 打印最终结果
    fmt.Println("子程序最终输出:")
    fmt.Print(output.String())
}

关键说明:

  • 使用bufio.Scanner逐行读取stdout,第一行就是目标问候语,无需等待流关闭
  • 写入stdin时必须添加换行符,匹配子程序ReadString('\n')的读取逻辑
  • 关闭stdin后,子程序会继续执行后续逻辑,此时可以继续读取stdout获取最终输出
  • 添加了错误处理,避免忽略潜在问题

内容的提问来源于stack exchange,提问作者cheveuxdelin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 09:18:27