英文:
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 (
"os/exec"
"time"
"bufio"
"math/rand"
"fmt"
"strings"
)
func main() {
cmd := exec.Command("e") // A simple program that echos input until it becomes "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 {
// Write stuff
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")
// Read stuff
time.Sleep(500 * time.Millisecond) // give the program time to generate output
input, err := buf.ReadString('\n')
if err != nil {
fmt.Println("I did *not* like that: ", input)
panic(err)
}
fmt.Println("Received: ", 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 (
"bufio"
"fmt"
"math/rand"
"os/exec"
"time"
)
func main() {
cmd := exec.Command("./e") // A simple program that echos input until it becomes "exit"
progin, err := cmd.StdoutPipe()
if err != nil {
fmt.Println("Trouble with e's stdout")
panic(err)
}
progout, err := cmd.StdinPipe()
if err != nil {
fmt.Println("Trouble with e's stdin")
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 {
// Write stuff
var toProg string
if r.Float64() < .1 {
toProg = "exit"
} else {
toProg = fmt.Sprintf("%d", r.Int())
}
fmt.Println("Printing: ", toProg)
progout.Write([]byte(toProg + "\n"))
// Read stuff
time.Sleep(500 * time.Millisecond) // give the program time to generate output
input, err := buf.ReadString('\n')
if err != nil {
fmt.Println("I did *not* like that: ", input)
panic(err)
}
fmt.Println("Received: ", input)
}
}
And e.go with a few fixups:
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("Echo failed: ", input)
panic(err)
}
if strings.HasPrefix(input, "exit") {
fmt.Println("Bye!")
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("%s", &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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论