Как я могу получить stdin для exec cmd в golang
У меня есть этот код
subProcess := exec.Cmd{
Path: execAble,
Args: []string{
fmt.Sprintf("-config=%s", *configPath),
fmt.Sprintf("-serverType=%s", *serverType),
fmt.Sprintf("-reload=%t", *reload),
fmt.Sprintf("-listenFD=%d", fd),
},
Dir: here,
}
subProcess.Stdout = os.Stdout
subProcess.Stderr = os.Stderr
logger.Info("starting subProcess:%s ", subProcess.Args)
if err := subProcess.Run(); err != nil {
logger.Fatal(err)
}
а затем я делаю os.Exit(1), чтобы остановить основной процесс
Я могу получить вывод из подпроцесса
но я также хочу поставить stdin в
Я пытаюсь
subProcess.Stdin = os.Stdin
но он не работает
Ответы
Ответ 1
Я сделал простую программу (для тестирования). Он считывает число и записывает указанный номер.
package main
import (
"fmt"
)
func main() {
fmt.Println("Hello, What your favorite number?")
var i int
fmt.Scanf("%d\n", &i)
fmt.Println("Ah I like ", i, " too.")
}
И вот модифицированный код
package main
import (
"fmt"
"io"
"os"
"os/exec"
)
func main() {
subProcess := exec.Command("go", "run", "./helper/main.go") //Just for testing, replace with your subProcess
stdin, err := subProcess.StdinPipe()
if err != nil {
fmt.Println(err) //replace with logger, or anything you want
}
defer stdin.Close() // the doc says subProcess.Wait will close it, but I'm not sure, so I kept this line
subProcess.Stdout = os.Stdout
subProcess.Stderr = os.Stderr
fmt.Println("START") //for debug
if err = subProcess.Start(); err != nil { //Use start, not run
fmt.Println("An error occured: ", err) //replace with logger, or anything you want
}
io.WriteString(stdin, "4\n")
subProcess.Wait()
fmt.Println("END") //for debug
}
Вам интересны эти строки
stdin, err := subProcess.StdinPipe()
if err != nil {
fmt.Println(err)
}
defer stdin.Close()
//...
io.WriteString(stdin, "4\n")
//...
subProcess.Wait()
Объяснение вышеприведенных строк
- Мы получаем подпроцесс 'stdin, теперь мы можем написать ему
- Мы используем свою силу, и мы пишем число
- Мы ожидаем завершения нашего подпроцесса
Выход
START
Привет, Какой ваш любимый номер? Мне тоже нравится 4. END
Для лучшего понимания
Ответ 2
Хотя этот вопрос немного стар, но вот мой ответ:
Этот вопрос, конечно, очень специфичен для платформы, так как управление стандартным IO зависит от реализации ОС, а не от языка Go. Однако, как общее правило (из-за преобладания некоторых ОС), "то, что вы просите, невозможно".
В большинстве современных операционных систем вы можете подключать стандартные потоки (как в ответе @mraron), вы можете отделить их (так работают демоны), но вы не можете переназначить или делегировать их другому процессу.
Я думаю, что это ограничение больше связано с соображениями безопасности. Есть все еще время от времени обнаруженные ошибки, которые позволяют удаленное выполнение кода, представьте, могла ли ОС переназначить/делегировать STDIN/OUT, тогда с такими уязвимостями последствия были бы катастрофическими.
Ответ 3
Пока вы не можете напрямую это сделать, поскольку @AlexKey написал ранее, вы можете сделать некоторые обходные пути. Если os не позволяет вам транслировать свои собственные стандартные потоки, которые волнуют все, что вам нужно, 2 канала и 2 goroutines
var stdinChan chan []byte
var stdoutChan chan []byte
//when something happens in stdout of your code just pipe it to stdout chan
stdoutChan<-somehowGotDataFromStdOut
тогда вам понадобятся две функции, как я упоминал ранее
func Pipein(){
for {
stdinFromProg.Write(<-stdInChan)
}
}
Та же идея для stdout