Когда вход для cypher-shell
является , а не (интерактивным) терминалом, он ожидает прочитать весь ввод и выполнить его как единый сценарий. «Весь ввод» означает «все до конца». Это типично для программ REPL: например, python
ведет себя так же.
Таким образом, ваш код Cypher даже не начнет выполняться, пока вы не stdin.Close()
. Ваш пример cmd.Stdout = os.Stdout
работает, потому что stdin
неявно закрывается при выходе из вашей программы Go, и только , тогда выполняет cypher-shell
, выполняет ваш код и печатает на стандартный вывод, который все еще подключен к вашему терминалу.
Возможно, вам следует структурировать ваш процесс по-другому. Например, вы не можете запустить новый cypher-shell
для каждого запроса?
Однако , если ничего не помогает, вы можете обойти это, обманув cypher-shell
, думая, что его стандартный является терминалом . Это называется «pty», и вы можете сделать это в Go с github.com/kr/pty
. Подвох в том, что он также 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
, потому что вы не используете какие-либо функции оболочки. Вы можете избежать накладных расходов дополнительного процесса оболочки, запустив cypher-shell
напрямую:
cmd := exec.Command("cypher-shell", "-u", "neo4j", "-p", "121314", "--format", "plain")
В сторону 2: Не сбрасывать возвращенные error
значения в производственном коде.