第一种方式:

func fork1() (*os.Process, error) {

	// 获取当前进程名和工作目录
	execName, err := os.Executable() // 输出与 os.Args[0] 类似
	if err != nil {
		return nil, err
	}
	// 生成子进程
	p, err := os.StartProcess(execName, []string{execName}, &os.ProcAttr{
		Dir: filepath.Dir(execName), //工作路径 不包含文件名
		Env: os.Environ(),           // 获取当前环境变量 并且传入子进程
		Files: []*os.File{
			os.Stdin,
			os.Stdout,
			os.Stderr,
		},
		Sys: &syscall.SysProcAttr{},
	})
	if err != nil {
		return nil, err
	}
	return p, nil
}
// 参考文章
// https://studygolang.com/articles/14038

第一种方式用法:

cmd, err := fork1()
	if err != nil {
		fmt.Println(err)
		return
	}
	log.Printf("fork1 pid=%v name=%v\n", cmd.Pid, filepath.Base(args[0]))
	os.Exit(0) // fork 进程后退出

第二种方式:

func fork2() (*exec.Cmd, error) {
	path, err := os.Executable() // 与 os.Args[0] 类似
	if err != nil {
		return nil, err
	}
	cmd := &exec.Cmd{
		Path:        path,               //文件路径 包括文件名
		Args:        []string{path},     //执行的命令
		Dir:         filepath.Dir(path), //文件路径 不包括文件名
		Env:         os.Environ(),       //环境变量
		Stdin:       os.Stdin,           // 输入
		Stdout:      os.Stdout,          // 输出
		Stderr:      os.Stderr,          // 错误
		SysProcAttr: &syscall.SysProcAttr{},
		/*		SysProcAttr: &syscall.SysProcAttr{
				Pdeathsig: syscall.SIGTERM,
			},*/
	}
	err = cmd.Start() // 不阻塞地执行
	if err != nil {
		return nil, err
	}
	/*	if err := cmd.Wait(); err != nil { // 阻塞
		log.Panicf("failed to wait command: %s", err)
	}*/
	return cmd, nil
}
// 参考文章
// https://blog.csdn.net/u013755520/article/details/106262434

第二种方式用法:

cmd, err := fork2()
	if err != nil {
		fmt.Println("error: ", err)
		return
	}
	fmt.Println("fork2 pid = ", cmd.Process.Pid) //获取pid
	os.Exit(0)                             // fork 进程后退出

第三种方式:

windows下不可用

var args = os.Args

func fork3() (error, int) {
	procAttr := &syscall.ProcAttr{
		Env:   os.Environ(),
		Files: []uintptr{os.Stdin.Fd(), os.Stdout.Fd(), os.Stderr.Fd()},
	}

	// windows下不可用
	pid, err := syscall.ForkExec(args[0], []string{args[0]}, procAttr) 
	if err != nil {
		return err, pid
	}
	return nil, pid
}
// 参考文章
// https://juejin.cn/post/6844903656891154446

第三种方式用法:

err, pid := fork3()
	if err != nil {
		fmt.Println("error", err)
		return
	}
	log.Println("fork3 pid=", pid)
	os,Exit(0) 	// fork 进程后退出