草庐IT

Go:按顺序接收 os.cmd stdout 和 stderr

coder 2023-06-26 原文

我需要从 go 执行子命令并分别处理它的 stdout 和 stderr,同时保持进入 stdin/stdout 的输出顺序。我尝试了几种不同的方法,但无法实现正确的输出顺序;以下代码显示输出处理顺序是绝对随机的:

package main

import (
    "fmt"
    "log"
    "os/exec"
)

var (
    result = ""
)

type writer struct {
    result string
    write  func(bytes []byte)
}

func (writer *writer) Write(bytes []byte) (int, error) {
    writer.result += string(bytes) // process result later
    result += string(bytes)
    return len(bytes), nil
}

func main() {
    cmd := exec.Command("bash", "-c", "echo TEST1; echo TEST2 1>&2; echo TEST3")

    stderr := &writer{}
    cmd.Stderr = stderr

    stdout := &writer{}
    cmd.Stdout = stdout

    err := cmd.Start()
    if err != nil {
        log.Fatal(err)
    }

    err = cmd.Wait()
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(result)
}

多次运行代码可以输出如下:

$ go run main.go
TEST1
TEST3
TEST2

我希望在所有情况下都能得到以下结果:

$ go run main.go
TEST1
TEST2
TEST3

我不能调用 cmd.CombinedOutput,因为我需要单独实时处理 stdout/stderr。

最佳答案

您正在执行的命令没有“顺序”。它们是并行管道,因此它们实际上是并发的,就像两个 goroutine 是并发的一样。您当然可以按照收到它们的顺序存储它们,并通过使用 channel 或互斥锁来标记它们的来源。为了使您的合成示例的输出不随机,您需要添加一点暂停。但是,我已将此方法成功地用于实际命令:

package main

import (
    "fmt"
    "log"
    "os/exec"
    "sync"
)

var (
    result = ""
)

type write struct {
    source string
    data   string
}

type writer struct {
    source string

    mu     *sync.Mutex
    writes *[]write
}

func (w *writer) Write(bytes []byte) (int, error) {
    w.mu.Lock()
    defer w.mu.Unlock()
    *w.writes = append(*w.writes, write{
            source: w.source,
            data:   string(bytes),
    })
    return len(bytes), nil
}

func main() {
    cmd := exec.Command("bash", "-c", "echo TEST1; sleep .1; echo TEST2 1>&2; sleep .1; echo TEST3")

    var mu sync.Mutex
    var writes []write

    cmd.Stderr = &writer{
            source: "STDERR",
            mu:     &mu,
            writes: &writes,
    }
    cmd.Stdout = &writer{
            source: "STDOUT",
            mu:     &mu,
            writes: &writes,
    }

    err := cmd.Start()
    if err != nil {
            log.Fatal(err)
    }

    err = cmd.Wait()
    if err != nil {
            log.Fatal(err)
    }

    fmt.Printf("%q\n", writes)
}

会产生

[{"STDOUT" "TEST1\n"} {"STDERR" "TEST2\n"} {"STDOUT" "TEST3\n"}]

关于Go:按顺序接收 os.cmd stdout 和 stderr,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32092275/

有关Go:按顺序接收 os.cmd stdout 和 stderr的更多相关文章

  1. ruby - Chef 执行非顺序配方 - 2

    我遵循了教程http://gettingstartedwithchef.com/,第1章。我的运行list是"run_list":["recipe[apt]","recipe[phpap]"]我的phpapRecipe默认Recipeinclude_recipe"apache2"include_recipe"build-essential"include_recipe"openssl"include_recipe"mysql::client"include_recipe"mysql::server"include_recipe"php"include_recipe"php::modul

  2. ruby-on-rails - RSpec:避免使用允许接收的任何实例 - 2

    我正在处理旧代码的一部分。beforedoallow_any_instance_of(SportRateManager).toreceive(:create).and_return(true)endRubocop错误如下:Avoidstubbingusing'allow_any_instance_of'我读到了RuboCop::RSpec:AnyInstance我试着像下面那样改变它。由此beforedoallow_any_instance_of(SportRateManager).toreceive(:create).and_return(true)end对此:let(:sport_

  3. ruby-on-rails - 如何在 mac os snow leopard 中升级 ruby​​ 和 rails - 2

    我想将我的MacSnowLeopardruby​​从1.8.7升级到1.9.1版本,有人知道轻松且最好的升级方法吗?因为我读了一些论坛/帖子/博客/讨论说覆盖苹果发布的ruby不好将Rails从版本2.2.2升级到2.3.8的最佳方法是什么?因为我找到的所有信息都仅适用于豹/老虎,而且很少有关于雪豹的复杂文章。他们还说覆盖apple提供的rails不好吗。谁能帮帮我?谢谢。 最佳答案 DanBenjamin有一些greatinstructionsforcompilingandinstallingRuby,RubyGemsandRai

  4. ruby-on-rails - 如何使用 Rack 接收 JSON 对象 - 2

    我有一个非常简单的RubyRack服务器,例如:app=Proc.newdo|env|req=Rack::Request.new(env).paramspreq.inspect[200,{'Content-Type'=>'text/plain'},['Somebody']]endRack::Handler::Thin.run(app,:Port=>4001,:threaded=>true)每当我使用JSON对象向服务器发送POSTHTTP请求时:{"session":{"accountId":String,"callId":String,"from":Object,"headers":

  5. SPI接收数据异常问题总结 - 2

    SPI接收数据左移一位问题目录SPI接收数据左移一位问题一、问题描述二、问题分析三、探究原理四、经验总结最近在工作在学习调试SPI的过程中遇到一个问题——接收数据整体向左移了一位(1bit)。SPI数据收发是数据交换,因此接收数据时从第二个字节开始才是有效数据,也就是数据整体向右移一个字节(1byte)。请教前辈之后也没有得到解决,通过在网上查阅前人经验终于解决问题,所以写一个避坑经验总结。实际背景:MCU与一款芯片使用spi通信,MCU作为主机,芯片作为从机。这款芯片采用的是它规定的六线SPI,多了两根线:RDY和INT,这样从机就可以主动请求主机给主机发送数据了。一、问题描述根据从机芯片手

  6. ruby-on-rails - 在 RSpec 中,如何以任意顺序期望具有不同参数的多条消息? - 2

    RSpec似乎按顺序匹配方法接收的消息。我不确定如何使以下代码工作:allow(a).toreceive(:f)expect(a).toreceive(:f).with(2)a.f(1)a.f(2)a.f(3)我问的原因是a.f的一些调用是由我的代码的上层控制的,所以我不能对这些方法调用添加期望。 最佳答案 RSpecspy是测试这种情况的一种方式。要监视一个方法,用allowstub,除了方法名称之外没有任何约束,调用该方法,然后expect确切的方法调用。例如:allow(a).toreceive(:f)a.f(2)a.f(1)

  7. ruby - 在 ruby​​ 中生成一个进程,捕获 stdout,stderr,获取退出状态 - 2

    我想从ruby​​rake脚本运行一个可执行文件,比如foo.exe我希望将foo.exe的STDOUT和STDERR输出直接写入我正在运行rake任务的控制台.当进程完成时,我想将退出代码捕获到一个变量中。我如何实现这一目标?我一直在玩backticks、process.spawn、system但我无法获得我想要的所有行为,只有部分更新:我在Windows上,在标准命令提示符下,而不是cygwin 最佳答案 system获取您想要的STDOUT行为。它还返回true作为零退出代码,这可能很有用。$?填充了有关最后一次system调

  8. ruby-on-rails - OS X Mavericks 破坏了 rbenv? - 2

    最近,我安装了OSXMavericks,它似乎弄乱了我的开发环境。我在运行“railsnewfirst_app”后收到此消息:Youruseraccountisn'tallowedtoinstalltothesystemRubygems.Youcancancelthisinstallationandrun:bundleinstall--pathvendor/bundletoinstallthegemsinto./vendor/bundle/,oryoucanenteryourpasswordandinstallthebundledgemstoRubygemsusingsudo.Pass

  9. ruby - 按数字(从大到大)然后按字母(字母顺序)对对象集合进行排序 - 2

    我正在构建一个小部件来显示奥运会的奖牌数。我有一个“国家”对象的集合,其中每个对象都有一个“名称”属性,以及奖牌计数的“金”、“银”、“铜”。列表应该排序:1.首先是奖牌总数2.如果奖牌相同,按类型分割(金>银>铜,即2金>1金+1银)3.如果奖牌和类型相同,则按字母顺序子排序我正在用ruby​​做这件事,但我想语言并不重要。我确实找到了一个解决方案,但如果感觉必须有更优雅的方法来实现它。这是我做的:使用加权奖牌总数创建一个虚拟属性。因此,如果他们有2个金牌和1个银牌,加权总数将为“3.020100”。1金1银1铜为“3.010101”由于我们希望将奖牌数排序为最高的,因此列表按降序排

  10. ruby-on-rails - 无法在 OS X Mavericks 中安装 gem 'therubyracer' - 2

    我是mac的新手,尝试bundleinstall一个克隆的railsrepo。我在安装libv8gem时遇到错误,google并找到了解决方案并做了brewinstalllibv8geminstalllibv8----with-system-v8接下来我中了thyreracergem,完整trace如下Buildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingtherubyracer:ERROR:Failedtobuildgemnativeextension./Users/anand/.rvm/rubies/

随机推荐