英文:
Call source from inside a Go program
问题
为了好玩和更好地学习Go语言,我正在尝试用Go重新实现antigen。
问题是:source
是一个shell内置函数,所以我无法使用os/exec
的Command
函数调用它,因为它期望在PATH
中找到一个可执行文件。
我该如何解决这个问题?而且,有没有可能让Go程序内部的source
影响用户的shell?
英文:
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?
答案1
得分: 0
你可以直接在终端设备中编写命令。但是,为了做到这一点,首先需要知道用户正在使用哪个设备。执行程序的脚本可以是一个解决方案。
#!/bin/bash
echo Running from foo script, pid = $$
go run foo.go `tty`
然后,程序必须将命令写入终端设备。
package main
import (
"C"
"fmt"
"os"
"syscall"
"unsafe"
)
func main() {
// 获取终端路径
if len(os.Args) < 2 {
fmt.Printf("no tty path\n")
os.Exit(1)
}
ttyPath := os.Args[1]
// 打开终端
tty, err := os.Open(ttyPath)
if err != nil {
fmt.Printf("error opening tty: %s\n", err.Error())
os.Exit(2)
}
defer tty.Close()
// 写入命令
cmd := "echo Hello from go, pid = $$\n"
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\n", err.Error())
os.Exit(3)
}
}
}
这是一个示例输出:
$ echo $$
70318
$ ./foo
Running from foo script, pid = 83035
echo Hello from go, pid = $$
$ echo Hello from go, pid = $$
Hello from go, pid = 70318
请注意,我使用./
而不是source
来执行脚本,因此脚本的PID不同。但是后来,由go程序执行的命令具有相同的PID。
英文:
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\n")
os.Exit(1)
}
ttyPath := os.Args[1]
// Open tty
tty, err := os.Open(ttyPath)
if err != nil {
fmt.Printf("error opening tty: %s\n", err.Error())
os.Exit(2)
}
defer tty.Close()
// Write a command
cmd := "echo Hello from go, pid = $$\n"
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\n", err.Error())
os.Exit(3)
}
}
}
Here is an example output:
<!-- language: none -->
$ 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论