对于不同的外壳命令,GO Exec的不同行为



我正在尝试将不同的shell命令用于控制台GO应用程序,由于某种原因,该行为对于以下交互式外壳而不同。

此代码打印了mongodb查询的结果:

cmd := exec.Command("sh", "-c", "mongo --quiet --host=localhost blog")
stdout, _ := cmd.StdoutPipe()
stdin, _ := cmd.StdinPipe()
stdoutScanner := bufio.NewScanner(stdout)
go func() {
    for stdoutScanner.Scan() {
        println(stdoutScanner.Text())
    }
}()
cmd.Start()
io.WriteString(stdin, "db.getCollection('posts').find({status:'ACTIVE'}).itcount()n")
//can't finish command, need to reuse it for other queries
//stdin.Close()
//cmd.Wait()
time.Sleep(2 * time.Second)

但是Neo4J Shell的相同代码没有打印任何东西:

cmd := exec.Command("sh", "-c", "cypher-shell -u neo4j -p 121314 --format plain")
stdout, _ := cmd.StdoutPipe()
stdin, _ := cmd.StdinPipe()
stdoutScanner := bufio.NewScanner(stdout)
go func() {
    for stdoutScanner.Scan() {
        println(stdoutScanner.Text())
    }
}()
cmd.Start()
io.WriteString(stdin, "match (n) return count(n);n")
//can't finish the command, need to reuse it for other queries
//stdin.Close()
//cmd.Wait()
time.Sleep(2 * time.Second)

有什么区别?我该如何使第二个工作?(不关闭命令(

P.SNeo4J直接打印到os.Stdout时工作正常:

cmd := exec.Command("sh", "-c", "cypher-shell -u neo4j -p 121314 --format plain")
cmd.Stdout = os.Stdout
stdin, _ := cmd.StdinPipe()
cmd.Start()
io.WriteString(stdin, "match (n) return count(n);n")
//stdin.Close()
//cmd.Wait()
time.Sleep(2 * time.Second)

cypher-shell的输入为不是 an(Interactive(终端时,它希望读取 toter单脚本。"整个输入"的意思是"一切直到EOF"。这对于REPP程序来说是典型的:例如,python的行为也是如此。

因此,直到您stdin.Close(),您的Cypher代码甚至才开始执行。您的cmd.Stdout = os.Stdout示例似乎有效,因为当您的GO程序退出时stdin已隐式关闭,并且仅然后 do cypher-shell执行您的代码并打印到STDOUT,该stdout仍连接到您的终端。

您可能应该以不同的方式构建过程。例如,您不能为每个查询运行新的cypher-shell吗?

但是,,如果其他所有失败,您可以通过欺骗cypher-shell以认为其stdin是终端来解决此问题。这称为" PTY",您可以使用github.com/kr/pty进行操作。 catch 是,这也使cypher-shell打印提示并回荡您的输入,如果您希望以编程方式处理输出,则必须检测并丢弃。

cmd := exec.Command("sh", "-c", "cypher-shell -u neo4j -p 121314 --format plain")
f, _ := pty.Start(cmd)
stdoutScanner := bufio.NewScanner(f)
cmd.Start()
// Give it some time to start, then read and discard the startup banner.
time.Sleep(2 * time.Second)
f.Read(make([]byte, 4096))
go func() {
    for stdoutScanner.Scan() {
        println(stdoutScanner.Text())
    }
}()
io.WriteString(f, "match (n) return count(n);n")
time.Sleep(2 * time.Second)
io.WriteString(f, "match (n) return count(n) + 123;n")
time.Sleep(2 * time.Second)

旁边1:在您的示例中,您不需要sh -c,因为您不使用Shell的任何功能。您可以直接运行cypher-shell来避免其他外壳过程的开销:

cmd := exec.Command("cypher-shell", "-u", "neo4j", "-p", "121314", "--format", "plain")

旁边2:不要丢弃返回的生产代码中的error值。

相关内容

最新更新