Panic
Panic

Reputation: 335

Run interactive shell script in golang program

I want to run an interactive shell script in golang program, such as wrap a "ping 8.8.8.8", "python", "bc", "mysql -H -P -u -p". The golang program should exit when itself finish calling an interactive command,or shell, and leaving spawned interactive with user.

I have tried the "exec.Command("python").Run()", but the golang program just finish and leave nothing to me.

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)
    }
}

Upvotes: 10

Views: 8961

Answers (2)

Shang Jian Ding
Shang Jian Ding

Reputation: 2126

Connect the Command's stdin, stdout, and stderr to those of the parent process. Also, supply -c in exec.Command to bash, else bash will try to run your program as if it's a shell script.

For example launching the interactive Python console:

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")
}

Upvotes: 26

David Maze
David Maze

Reputation: 158758

It sounds like you want to replace the current process with the command you're trying to launch. After you launch the other command, your Go program is gone, and the caller interacts with the launched program as if it were the thing that was initially started.

You need the low-level syscall.Exec function for this. You shouldn't normally expect it to return. Note that you need to provide a number of details like the actual binary to run and the environment that the higher-level wrappers don't need. (A very quick Google search finds this detailed writeup.)

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)

In terms of the underlying Unix system calls, the higher-level interfaces like os.StartProcess and the exec.Cmd all fork(2) a child process first before execve(2) in that child. When your Go process exits, that child process becomes orphaned, and the system init process becomes its new parent. The shell just sees that the Go process has exited and will produce a new shell prompt.

Upvotes: 7

Related Questions