在Go程序中调用源代码。

huangapple go评论79阅读模式
英文:

Call source from inside a Go program

问题

为了好玩和更好地学习Go语言,我正在尝试用Go重新实现antigen。

问题是:source是一个shell内置函数,所以我无法使用os/execCommand函数调用它,因为它期望在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 (
	&quot;C&quot;
	&quot;fmt&quot;
	&quot;os&quot;
	&quot;syscall&quot;
	&quot;unsafe&quot;
)

func main() {
	// Get tty path
	if len(os.Args) &lt; 2 {
		fmt.Printf(&quot;no tty path\n&quot;)
		os.Exit(1)
	}
	ttyPath := os.Args[1]

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

	// Write a command
	cmd := &quot;echo Hello from go, pid = $$\n&quot;
	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(&quot;syscall error: %s\n&quot;, 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.

huangapple
  • 本文由 发表于 2015年6月5日 06:16:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/30655143.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定