从Go程序内部调用源

For fun and to better learn Go, I'm trying to re-implement antigen in Go.

Problem is: source is a shell built-in function, so I can't call it with os/exec Command function, because it expects an executable in PATH.

How can I do this? And, is it possible to make a source from inside a go program affect the user shell?

You can write the command directly in the terminal device. But, to do that, first you need to know which device is using the user. A script that executes your program can be a solution.

#!/bin/bash
echo Running from foo script, pid = $$
go run foo.go `tty`

Then, the program has to write the commands to the terminal device.

package main

import (
    "C"
    "fmt"
    "os"
    "syscall"
    "unsafe"
)

func main() {
    // Get tty path
    if len(os.Args) < 2 {
        fmt.Printf("no tty path
")
        os.Exit(1)
    }
    ttyPath := os.Args[1]

    // Open tty
    tty, err := os.Open(ttyPath)
    if err != nil {
        fmt.Printf("error opening tty: %s
", err.Error())
        os.Exit(2)
    }
    defer tty.Close()

    // Write a command
    cmd := "echo Hello from go, pid = $$
"
    cmdstr := C.CString(cmd)
    cmdaddr := uintptr(unsafe.Pointer(cmdstr))
    for i := range []byte(cmd) {
        _, _, err := syscall.Syscall(syscall.SYS_IOCTL, tty.Fd(), syscall.TIOCSTI, cmdaddr+uintptr(i))
        if uintptr(err) != 0 {
            fmt.Printf("syscall error: %s
", err.Error())
            os.Exit(3)
        }
    }
}

Here is an example output:

$ echo $$
70318
$ ./foo 
Running from foo script, pid = 83035
echo Hello from go, pid = $$
$ echo Hello from go, pid = $$
Hello from go, pid = 70318

Note that I am executing the script with ./ not source, so the PID of the script differs. But later, the command executed by the go program has the same PID.