在 golang 程序中运行交互式 shell 脚本

Pan*_*nic 4 go

我想在golang程序中运行一个交互式shell脚本,比如包装一个“ping 8.8.8.8”、“python”、“bc”、“mysql -H -P -u -p”。golang 程序应该在它自己完成调用交互式命令或 shell 并与用户保持交互时退出。

我已经尝试过“exec.Command(“python”).Run()”,但是golang 程序刚刚完成并且没有留下任何东西给我。

func (h ConnectHandler)ConnectMySQL()  {
    logrus.Debug("ConnectMySQL, script:",common.CONF.FilePath.MySQLConnectScriptPath)
    err :=exec.Command("bash",common.CONF.FilePath.MySQLConnectScriptPath).Run()
    if err != nil{
        logrus.Errorf("ConnectMySQL failed, exit 1,%s",err)
        os.Exit(1)
    }
}
Run Code Online (Sandbox Code Playgroud)

Sha*_*ing 6

将 Command 的 stdin、stdout 和 stderr 连接到父进程的 stdin、stdout 和 stderr。此外,提供-cin exec.Commandto bash,否则bash将尝试像运行 shell 脚本一样运行您的程序。

例如启动交互式 Python 控制台:

func main() {
    fmt.Println("Before Python shell:")
    cmd := exec.Command("bash", "-c", "/usr/bin/python3")
    cmd.Stdin = os.Stdin
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr
    _ = cmd.Run() // add error checking
    fmt.Println("After Python shell")
}
Run Code Online (Sandbox Code Playgroud)

  • 这个方法效果很好。我不明白,为什么它没有收到任何赞成票。 (2认同)

Dav*_*aze 6

听起来您想用您尝试启动的命令替换当前进程。启动另一个命令后,您的 Go 程序就消失了,调用者与启动的程序进行交互,就好像它是最初启动的一样。

为此,您需要低级syscall.Exec函数。通常您不应期望它会返回。请注意,您需要提供许多详细信息,例如要运行的实际二进制文件以及更高级别包装器不需要的环境。(非常快速的谷歌搜索找到了这篇详细的文章。)

import "os"
import "syscall"
err := syscall.Exec("/bin/ls", []string{"ls", "-l", "/"}, os.Environ())
// We don't expect this to ever return; if it does something is really wrong
os.panic(err)
Run Code Online (Sandbox Code Playgroud)

就底层 Unix 系统调用而言,更高级别的接口如os.StartProcessall exec.Cmdfork ( 2) 子进程,然后在该子进程中执行execve (2)。当您的 Go 进程退出时,该子进程将成为孤儿进程,系统 init 进程将成为其新的父进程。shell 只是看到 Go 进程已经退出,并会产生一个新的 shell 提示符。