我一直在尝试编写一个程序,该程序记录传递给子进程的内容,并且控制台实时返回(将来,要记录SSH session ,现在在Python Shell上进行测试)
我可以记录而不会发出stdout和stderr(它显示并正确记录了它),但是我找不到在stdin上执行相同操作的方法吗?
基本上,我的标准输入都将映射到子进程标准输入并写入日志文件。
这是我当前的代码:
func SSH(cmd *cobra.Command, args []string) {
logFile := fmt.Sprintf("%v@%s.log", args[0], time.Now().Format(SSHLogDateFormat))
usr, _ := user.Current()
home := usr.HomeDir
logDir := fmt.Sprintf("%s/%s/logs", home, config.ConfigDir)
if _, err := os.Stat(logDir); os.IsNotExist(err) {
err = os.Mkdir(logDir, os.FileMode(int(0700)))
if err != nil {
log.Fatalf("Failed to create %s: %s", logDir, err)
}
}
fullLogFile := fmt.Sprintf("%s/%s", logDir, logFile)
log.Infof("Started recording to %s", fullLogFile)
bash, err := exec.LookPath("bash")
if err != nil {
log.Errorf("Could not locate bash: %v", err)
}
f, err := os.Create(fullLogFile)
if err != nil {
log.Fatalf("Failed to open device logs: %s", err)
}
command := exec.Command(bash, "-c", "python")
out := io.MultiWriter(os.Stdout, f)
command.Stderr = out
command.Stdout = out
if err := command.Start(); nil != err {
log.Fatalf("Error starting program: %s, %s", command.Path, err.Error())
}
err = command.Wait()
if err != nil {
log.Fatalf("Error waiting program: %s, %s", command.Path, err.Error())
}
f.Close()
log.Infof("Finished recording to %s", fullLogFile)
}
也尝试了这个但没有成功:
out := io.MultiWriter(os.Stdout, f)
in := io.TeeReader(os.Stdin, out)
command.Stderr = out
command.Stdout = out
command.Stdin = in
最佳答案
您需要写入进程的stdin
。得到一个写管道:
procIn, err := command.StdinPipe()
if nil!=err {
log.Fatal(err)
}
然后创建一个multiWriter以写入日志和进程:
inWriter := io.MultiWriter(procIn, f)
最后,将Stdin复制到MultiWriter中:
go func() {
io.Copy(inWriter, os.Stdin)
procIn.Close()
}()
我们在goroutine中进行复制,以免挂起所有内容:我们尚未启动命令,因此没有任何内容接收写入的字节。它需要与命令运行并行发生。
这是一个非常简单的示例:
package main
import (
`os`
`os/exec`
`io`
)
// pipeto copies stdin to logOut and to the command,
// and copies the commands stdout and stderr to logOut and
// to our stderr.
func pipeto(logOut os.Writer, cmd string, args ...string) error {
cmd := exec.Command(cmd, args...)
out := io.MultiWriter(os.Stdout, logOut)
cmd.Stderr, cmd.Stdout = out, out
procIn, err := cmd.StdinPipe()
if nil!=err {
return err
}
go func() {
io.Copy( io.MultiWriter(procIn, logOut) , os.Stdin )
procIn.Close()
}()
return cmd.Run()
}
func main() {
logOut, err := os.Create(`logout.log`)
if nil!=err {
panic(err)
}
defer logOut.Close()
if err := pipeto(logOut, `sed`, `s/tea/coffee/g`); nil!=err {
panic(err)
}
}
您可以在我将go文件命名为
pipetest.go
的情况下进行测试:echo this is a test of tea | go run pipetest.go
您将在
logout.log
中看到输入和输出:this is a test of tea
this is a test of coffee
关于go - 如何在Go中打开进程并正确记录stdin和stdout?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59093034/