Go语言中的持久化程序

huangapple go评论82阅读模式
英文:

Persistent program in Go

问题

我正在尝试学习Go语言,并且想从一个我一直想做但似乎太过繁琐的项目开始。基本的想法是,我有一个与用户在stdin/stdout上交互的程序,我想编写一个新的程序,以相同的方式与该程序交互(就像一个人在运行该程序一样)。

现在这个程序很简单,因为它是同步的:你输入一个命令,得到一些输出,然后它就会等待下一批输入。这似乎并不难,但我在让这个I/O框架工作时遇到了麻烦。

package main

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

func main() {
	cmd := exec.Command("e")	// 一个简单的程序,它会将输入内容回显直到输入为"exit"

	progin, err := cmd.StdoutPipe()
	if err != nil {
		fmt.Println("Trouble with e's stdout")
		panic(err)
	}

	err = cmd.Start()
	if err != nil {
		fmt.Println("Trouble starting e")
		panic(err)
	}
	
	r := rand.New(rand.NewSource(99))

	buf := bufio.NewReader(progin)
	for {
		// 写入内容
		var toProg string
		if (r.Float64() < .1) {
			toProg = "exit"
		} else {
			toProg = fmt.Sprintf("%d", r.Int())
		}
		fmt.Println("Printing: ", toProg)
		cmd.Stdin = strings.NewReader(toProg + "\n")
		
		// 读取内容
		time.Sleep(500 * time.Millisecond) // 给程序一些时间生成输出

		input, err := buf.ReadString('\n')
		if err != nil {
			fmt.Println("I did *not* like that: ", input)
			panic(err)
		}
		fmt.Println("Received: ", input)
		
	}
}

有人愿意接手吗?

英文:

I'm trying to learn Go, and I thought I'd start with a project I've wanted to do for some time (but which seemed too 'fiddly' to bother with). The essential idea is that I have a program which interacts with the user on stdin/stdout and I'd like to write a new program which interacts with the program in the same way (as if it were a person running the program).

Now the program here is simple, in that it's synchronous: you enter a command, get some output, and then it sits there waiting for the next batch of input. That didn't seem so hard, but I'm having trouble getting this I/O skeleton working.

package main

import (
	&quot;os/exec&quot;
	&quot;time&quot;
	&quot;bufio&quot;
	&quot;math/rand&quot;
	&quot;fmt&quot;
	&quot;strings&quot;
)

func main() {
	cmd := exec.Command(&quot;e&quot;)	// A simple program that echos input until it becomes &quot;exit&quot;

	progin, err := cmd.StdoutPipe()
	if err != nil {
		fmt.Println(&quot;Trouble with e&#39;s stdout&quot;)
		panic(err)
	}

	err = cmd.Start()
	if err != nil {
		fmt.Println(&quot;Trouble starting e&quot;)
		panic(err)
	}
	
	r := rand.New(rand.NewSource(99))

	buf := bufio.NewReader(progin)
	for {
		// Write stuff
		var toProg string
		if (r.Float64() &lt; .1) {
			toProg = &quot;exit&quot;
		} else {
			toProg = fmt.Sprintf(&quot;%d&quot;, r.Int)
		}
		fmt.Println(&quot;Printing: &quot;, toProg)
		cmd.Stdin = strings.NewReader(toProg + &quot;\n&quot;)
		
		// Read stuff
		time.Sleep(500 * time.Millisecond) // give the program time to generate output

		input, err := buf.ReadString(&#39;\n&#39;)
		if err != nil {
			fmt.Println(&quot;I did *not* like that: &quot;, input)
			panic(err)
		}
		fmt.Println(&quot;Received: &quot;, input)
		
	}
}

Any takers?

答案1

得分: 1

你最大的问题是重新分配了命令的 Stdin,而不是将其作为管道传递给它。

这是一个可工作的版本:

package main

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

func main() {
	cmd := exec.Command("./e") // 一个简单的程序,将输入回显直到输入为 "exit"

	progin, err := cmd.StdoutPipe()
	if err != nil {
		fmt.Println("e 的标准输出出现问题")
		panic(err)
	}

	progout, err := cmd.StdinPipe()
	if err != nil {
		fmt.Println("e 的标准输入出现问题")
		panic(err)
	}

	err = cmd.Start()
	if err != nil {
		fmt.Println("启动 e 出现问题")
		panic(err)
	}

	r := rand.New(rand.NewSource(99))

	buf := bufio.NewReader(progin)
	for {
		// 写入内容
		var toProg string
		if r.Float64() < .1 {
			toProg = "exit"
		} else {
			toProg = fmt.Sprintf("%d", r.Int())
		}
		fmt.Println("输出:", toProg)
		progout.Write([]byte(toProg + "\n"))

		// 读取内容
		time.Sleep(500 * time.Millisecond) // 给程序生成输出的时间

		input, err := buf.ReadString('\n')
		if err != nil {
			fmt.Println("我不喜欢这个:", input)
			panic(err)
		}
		fmt.Println("接收到:", input)

	}
}

还有 e.go,做了一些修正:

package main

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

func main() {
	for {
		buf := bufio.NewReader(os.Stdin)
		input, err := buf.ReadString('\n')

		if err != nil {
			fmt.Println("回显失败:", input)
			panic(err)
		}

		if strings.HasPrefix(input, "exit") {
			fmt.Println("再见!")
			return
		}

		fmt.Print(input)
	}
}

希望对你有帮助!

英文:

Your biggest issue is you're reassigning the command's Stdin, instead of piping to it.

Here's a working version:

package main
import (
&quot;bufio&quot;
&quot;fmt&quot;
&quot;math/rand&quot;
&quot;os/exec&quot;
&quot;time&quot;
)
func main() {
cmd := exec.Command(&quot;./e&quot;) // A simple program that echos input until it becomes &quot;exit&quot;
progin, err := cmd.StdoutPipe()
if err != nil {
fmt.Println(&quot;Trouble with e&#39;s stdout&quot;)
panic(err)
}
progout, err := cmd.StdinPipe()
if err != nil {
fmt.Println(&quot;Trouble with e&#39;s stdin&quot;)
panic(err)
}
err = cmd.Start()
if err != nil {
fmt.Println(&quot;Trouble starting e&quot;)
panic(err)
}
r := rand.New(rand.NewSource(99))
buf := bufio.NewReader(progin)
for {
// Write stuff
var toProg string
if r.Float64() &lt; .1 {
toProg = &quot;exit&quot;
} else {
toProg = fmt.Sprintf(&quot;%d&quot;, r.Int())
}
fmt.Println(&quot;Printing: &quot;, toProg)
progout.Write([]byte(toProg + &quot;\n&quot;))
// Read stuff
time.Sleep(500 * time.Millisecond) // give the program time to generate output
input, err := buf.ReadString(&#39;\n&#39;)
if err != nil {
fmt.Println(&quot;I did *not* like that: &quot;, input)
panic(err)
}
fmt.Println(&quot;Received: &quot;, input)
}
}

And e.go with a few fixups:

package main
import (
&quot;bufio&quot;
&quot;fmt&quot;
&quot;os&quot;
&quot;strings&quot;
)
func main() {
for {
buf := bufio.NewReader(os.Stdin)
input, err := buf.ReadString(&#39;\n&#39;)
if err != nil {
fmt.Println(&quot;Echo failed: &quot;, input)
panic(err)
}
if strings.HasPrefix(input, &quot;exit&quot;) {
fmt.Println(&quot;Bye!&quot;)
return
}
fmt.Print(input)
}
}

答案2

得分: 0

你有点在重复造轮子,你想做的一切都可以通过fmt包来处理,所以只需使用它并在需要时添加额外的内容,比如随机数检查器。

以下是一个简单实现的示例:http://play.golang.org/p/b9GNovSRFj

这个策略的主要功能如下:

var s string
_, err := fmt.Scanf("%s", &s)
if err != nil {
    log.Fatal(err)
}
fmt.Println(s)

请注意,由于权限问题,它无法在playground中运行,但如果在本地运行应该可以正常工作。

英文:

You're kind of reinventing the wheel, everything you want to do can be handled by the <code>fmt</code> package, so just use that and add in the extra stuff like the random number checker where it is needed.

Here is an example of how to achieve this easily: http://play.golang.org/p/b9GNovSRFj

And for a quick look, the main functionality of this strategy:

var s string
_, err := fmt.Scanf(&quot;%s&quot;, &amp;s)
if err != nil {
log.Fatal(err)
}
fmt.Println(s)

Note that it will not run in the playground due to permission issues, but if you run it locally it should work fine.

huangapple
  • 本文由 发表于 2013年10月30日 04:25:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/19668374.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定