Golang中实现交互式bash的方法
Golang中实现交互式bash的方法 团队,
我有一个小的“Hello World” Go 例程,它调用 shell 脚本 hello.sh。 在 hello.sh 中,我编写了一段代码来提示用户输入并简单地打印该输入。 在 hello.go 的 Go 例程中,我需要将控制权传递给 shell 脚本 (hello.sh),以便它能像代码中那样直接要求用户输入。以下是供参考的代码。
Hello.go
package main
import (
"fmt"
//"log"
"os/exec"
"bytes"
//"syscall"
//"bufio"
"os"
//"time"
//"strings"
)
func main() {
fmt.Printf("hello, world\n")
var out bytes.Buffer
var stderr bytes.Buffer
cmd := exec.Command("/bin/sh", "/Users/z003swb/go/nagy/src/hello.sh")
cmd.Stdout = &out
cmd.Stderr = &stderr
cmd.Stdin = os.Stdin
cmd.Run()
fmt.Printf("%s\n", out.String())
}
Hello.sh
echo ""
echo "Calling Hello sh script at `date`"
echo "Hai at `date`"
echo "Do you want to say Yes|No?"
read name
echo "respone was : $name"
echo "Bye at `date`"
我的问题/需要帮助?
+++++++++++++++++++++++++
我希望在执行时显示 shell 中的命令 echo "Do you want to say Yes|No?" 并接收用户的输入。
目前,通过设置 cmd.Stdin = os.Stdin,我能够将值传递给 shell,但我无法直接从 shell 代码中获得调用。
执行示例
$ ./hello
hello, world
yes
Calling Hello sh script at Thu May 6 11:32:07 IST 2021
Hai at Thu May 6 11:32:07 IST 2021
Do you want to say Yes|No?
respone was : yes
Bye at Thu May 6 11:32:10 IST 2021
但是,我如何让 shell 在执行时询问输入并显示“Do you want to say Yes|No?”?有什么方法可以实现这一点吗?请帮助。我是一个初学者,所以需要专业的帮助。谢谢。
更多关于Golang中实现交互式bash的方法的实战教程也可以访问 https://www.itying.com/category-94-b0.html
你好,非常感谢你的回复。但是,我该如何让它提示输入“echo ‘Do you want to say Yes|No?’”呢?这个提示在 hello.sh 脚本里。目前这个提示没有出现,这就是问题所在。
我需要通过 Go 代码来调用/提示从 shell 获取输入,并通过 Go 代码将响应返回给 shell。
再次非常感谢你的帖子。
更多关于Golang中实现交互式bash的方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
gucio321 提到,如果你想看到 hello.sh 的提示信息并能够通过终端进行响应,那么将命令的 Stdout 设置为 os.Stdout,Stderr 设置为 os.Stderr。这样 hello.sh 就能像在 shell 中直接运行一样与终端进行交互。
naguram: 我需要通过 Go 代码从 shell 调用/提示输入,并通过 Go 将响应返回给 shell。
我不太确定你这里具体想要什么。你是希望用户通过 shell 看到并与 hello.sh 交互,还是希望你的 Go 程序拦截并响应它?
正如其他人所指出的,你可以直接将 Stdin/out/error 分配给 os:
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
不过,我敢打赌你没有得到任何提示/输出的原因是 cmd.Run 返回了一个错误,而你却没有处理它。修改这行代码来检查错误:
// 将这一行...
cmd.Run()
// ... 改为这样:
if err := cmd.Run(); err != nil {
fmt.Println(err)
}
……我敢打赌你会得到一个能确切告诉你问题所在的错误。
编辑:我没意识到我在这里来得这么晚。哎呀。
你不需要使用 bytes.Buffer 作为输出。
你可以直接这样做:cmd.Stdout = os.Stdout; cmd.Stderr = os.Stderr
你也可以编写自己的 io.Writer 实现,例如:
type writer struct {
w bytes.Buffer
}
func (w *writer) Write(b []byte) (n int, err error) {
n1, err := os.Stdout.Write(b)
if err != nil {
return n1, err
}
n2, err := w.w.Write(b)
if err != nil {
return n2, err
}
return len(b), nil
}
func (w *writer) String() string { return w.w.String() }
*当然,Write 方法应该检查每个 n1 和 n2。
在Golang中实现交互式bash,关键在于正确设置标准输入输出。你的代码已经接近正确,但需要确保shell脚本的提示能实时显示。以下是修改后的示例:
package main
import (
"fmt"
"os"
"os/exec"
"syscall"
)
func main() {
fmt.Printf("hello, world\n")
cmd := exec.Command("/bin/sh", "/Users/z003swb/go/nagy/src/hello.sh")
// 关键设置:将标准输入、输出、错误直接连接到终端
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
// 设置终端控制
cmd.SysProcAttr = &syscall.SysProcAttr{
Setpgid: true,
Ctty: int(os.Stdin.Fd()),
}
err := cmd.Run()
if err != nil {
fmt.Printf("Command execution error: %v\n", err)
}
}
或者使用更简单的方法,直接传递-i参数启用交互模式:
package main
import (
"fmt"
"os"
"os/exec"
)
func main() {
fmt.Printf("hello, world\n")
// 使用-i参数启用交互模式
cmd := exec.Command("/bin/sh", "-i", "/Users/z003swb/go/nagy/src/hello.sh")
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
if err != nil {
fmt.Printf("Error: %v\n", err)
}
}
如果仍然遇到缓冲问题,可以使用pty创建伪终端:
package main
import (
"fmt"
"os"
"os/exec"
"github.com/creack/pty"
"io"
)
func main() {
fmt.Printf("hello, world\n")
cmd := exec.Command("/bin/sh", "/Users/z003swb/go/nagy/src/hello.sh")
// 创建伪终端
ptmx, err := pty.Start(cmd)
if err != nil {
panic(err)
}
defer ptmx.Close()
// 复制标准输入输出
go func() {
io.Copy(ptmx, os.Stdin)
}()
io.Copy(os.Stdout, ptmx)
cmd.Wait()
}
注意:使用pty方法需要先安装依赖:go get github.com/creack/pty
第一种方法应该能解决你的问题,它会确保shell脚本的提示信息实时显示,并正确接收用户输入。

