我想在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)
将 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)
听起来您想用您尝试启动的命令替换当前进程。启动另一个命令后,您的 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 提示符。