我需要从 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/
我遵循了教程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
我正在处理旧代码的一部分。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_
我想将我的MacSnowLeopardruby从1.8.7升级到1.9.1版本,有人知道轻松且最好的升级方法吗?因为我读了一些论坛/帖子/博客/讨论说覆盖苹果发布的ruby不好将Rails从版本2.2.2升级到2.3.8的最佳方法是什么?因为我找到的所有信息都仅适用于豹/老虎,而且很少有关于雪豹的复杂文章。他们还说覆盖apple提供的rails不好吗。谁能帮帮我?谢谢。 最佳答案 DanBenjamin有一些greatinstructionsforcompilingandinstallingRuby,RubyGemsandRai
我有一个非常简单的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":
SPI接收数据左移一位问题目录SPI接收数据左移一位问题一、问题描述二、问题分析三、探究原理四、经验总结最近在工作在学习调试SPI的过程中遇到一个问题——接收数据整体向左移了一位(1bit)。SPI数据收发是数据交换,因此接收数据时从第二个字节开始才是有效数据,也就是数据整体向右移一个字节(1byte)。请教前辈之后也没有得到解决,通过在网上查阅前人经验终于解决问题,所以写一个避坑经验总结。实际背景:MCU与一款芯片使用spi通信,MCU作为主机,芯片作为从机。这款芯片采用的是它规定的六线SPI,多了两根线:RDY和INT,这样从机就可以主动请求主机给主机发送数据了。一、问题描述根据从机芯片手
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)
我想从rubyrake脚本运行一个可执行文件,比如foo.exe我希望将foo.exe的STDOUT和STDERR输出直接写入我正在运行rake任务的控制台.当进程完成时,我想将退出代码捕获到一个变量中。我如何实现这一目标?我一直在玩backticks、process.spawn、system但我无法获得我想要的所有行为,只有部分更新:我在Windows上,在标准命令提示符下,而不是cygwin 最佳答案 system获取您想要的STDOUT行为。它还返回true作为零退出代码,这可能很有用。$?填充了有关最后一次system调
最近,我安装了OSXMavericks,它似乎弄乱了我的开发环境。我在运行“railsnewfirst_app”后收到此消息:Youruseraccountisn'tallowedtoinstalltothesystemRubygems.Youcancancelthisinstallationandrun:bundleinstall--pathvendor/bundletoinstallthegemsinto./vendor/bundle/,oryoucanenteryourpasswordandinstallthebundledgemstoRubygemsusingsudo.Pass
我正在构建一个小部件来显示奥运会的奖牌数。我有一个“国家”对象的集合,其中每个对象都有一个“名称”属性,以及奖牌计数的“金”、“银”、“铜”。列表应该排序:1.首先是奖牌总数2.如果奖牌相同,按类型分割(金>银>铜,即2金>1金+1银)3.如果奖牌和类型相同,则按字母顺序子排序我正在用ruby做这件事,但我想语言并不重要。我确实找到了一个解决方案,但如果感觉必须有更优雅的方法来实现它。这是我做的:使用加权奖牌总数创建一个虚拟属性。因此,如果他们有2个金牌和1个银牌,加权总数将为“3.020100”。1金1银1铜为“3.010101”由于我们希望将奖牌数排序为最高的,因此列表按降序排
我是mac的新手,尝试bundleinstall一个克隆的railsrepo。我在安装libv8gem时遇到错误,google并找到了解决方案并做了brewinstalllibv8geminstalllibv8----with-system-v8接下来我中了thyreracergem,完整trace如下Buildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingtherubyracer:ERROR:Failedtobuildgemnativeextension./Users/anand/.rvm/rubies/