1

I am looking for a way to launch a completely independent instance of a program from within a Go program. So far this is my best attempt:

  // Some code   

    go exec.Command("konsole", "--hold", "--separate", "sh", "-e", "go", "run", "test.go")
.Run()

    // Continue doing something else then quit

Using linux KDE's Konsole. This command "almost" works - it starts a new Konsole instance and runs the program. But they are dependent: if the first program is ended (ctrl+c), the second also ends. Is there a way to work around this problem?

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
Erik
  • 31
  • 6
  • 2
    This has nothing to do with the child process (really the child of the child of the child process) being a Go program. – Adrian Feb 21 '20 at 18:04
  • @Adrian fair enough, I changed it to just program. – Erik Feb 21 '20 at 18:11
  • 1
    A program running in the background, independent from the one it was started from and with its output streams closed or redirected to a logfile is called "daemon". Running a process as daemon is not just a single call, but these keywords should give you a hint. Maybe https://stackoverflow.com/questions/10027477/how-to-fork-a-process would help. – Ulrich Eckhardt Feb 21 '20 at 18:42
  • If Ctrl-C is the main issue, you can just put it in a different process group – that other guy Feb 21 '20 at 18:49

1 Answers1

2

In order to achieve it you need to replace exec.Command call with os.StartProcess giving extra process attributes os.ProcAttr and syscall.SysProcAttr. Setting flag Setpgid and leaving Pgid with default value of 0 achieves to goal as mentioned by @that_other_guy.

package main

import (
        "fmt"
        "os"
        "os/exec"
        "syscall"
)

func main() {
        cmd, err := exec.LookPath("sleep")
        if err != nil {
                panic(err)
        }
        attr := &os.ProcAttr{
                Sys: &syscall.SysProcAttr{
                        Setpgid: true,
                },
        }
        process, err := os.StartProcess(cmd, []string{cmd, "1m"}, attr)
        if err != nil {
                panic(err)
        }
        fmt.Println(process.Pid)
        process.Release()
        for {
        }
        return
}
Grzegorz Żur
  • 47,257
  • 14
  • 109
  • 105