为什么这个对不同打开的 tty 的 exec.Command 不正常工作?

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

Why does this exec.Command to a different opened tty not work properly

问题

有人可以帮我弄清楚我在这里做错了什么吗?

我试图执行一个命令(在这种情况下是打开vim),该命令在不同的tty中运行,即/dev/ttys001,在我的终端中的另一个选项卡中打开。

运行下面的代码确实在/dev/ttys001的窗口中显示了vim,但是从该窗口实际键入的内容无法正确注册。

非常感谢任何建议!

package main

import (
	"log"
	"os"
	"os/exec"
)

func main() {
	tty, err := os.OpenFile("/dev/ttys001", os.O_RDWR, os.ModePerm)
	if err != nil {
		log.Fatalln(err)
	}
	defer tty.Close()

	c := exec.Command("vim")
	c.Stdin = tty
	c.Stdout = tty
	c.Stderr = tty
	if err := c.Run(); err != nil {
		log.Fatalln(err)
	}
}

我还尝试使用以下代码设置命令的SysProcAttr字段,但是收到错误消息:fork/exec /usr/local/bin/vim: inappropriate ioctl for device.

procAttr := &syscall.SysProcAttr{
	Setpgid:    true,
	Ctty:       int(tty.Fd()),
	Foreground: true,
}
c.SysProcAttr = procAttr
英文:

Can anybody please help me figure out what I'm doing wrong here.

I'm trying to execute a command (opening vim in this case) that runs in a different tty, in this case /dev/ttys001, which is opened in another tab in my terminal.

Running the code below does render vim in /dev/ttys001's window, however, actually typing to stdin from that window doesn't register properly.

Any advice is much appreciated!

package main

import (
	"log"
	"os"
	"os/exec"
)

func main() {
	tty, err := os.OpenFile("/dev/ttys001", os.O_RDWR, os.ModePerm)
	if err != nil {
		log.Fatalln(err)
	}
	defer tty.Close()

	c := exec.Command("vim")
	c.Stdin = tty
	c.Stdout = tty
	c.Stderr = tty
	if err := c.Run(); err != nil {
		log.Fatalln(err)
	}
}

I have also tried setting the command's SysProcAttr field with the following code but receive the error: fork/exec /usr/local/bin/vim: inappropriate ioctl for device.

procAttr := &syscall.SysProcAttr{
	Setpgid:    true,
	Ctty:       int(tty.Fd()),
	Foreground: true,
}
c.SysProcAttr = procAttr

答案1

得分: 0

对于任何感兴趣的人,我想出了一个解决方案,但最终不得不使用系统调用而不是os/exec包的函数。

package main

import (
	"log"
	"os"
	"syscall"
	"unsafe"
)

var tty = "/dev/ttys001"
var cmd = "vim\n"

func main() {
	ttyFile, err := os.Open(tty)
	if err != nil {
		log.Fatalln(err)
	}
	defer ttyFile.Close()

	cbs, err := syscall.ByteSliceFromString(cmd)
	if err != nil {
		log.Fatalln(err)
	}

	var eno syscall.Errno
	for _, c := range cbs {
		_, _, eno = syscall.Syscall(syscall.SYS_IOCTL,
			ttyFile.Fd(),
			syscall.TIOCSTI,
			uintptr(unsafe.Pointer(&c)),
		)
		if eno != 0 {
			log.Fatalln(eno)
		}
	}
}

希望对你有帮助!

英文:

For anybody who's interested, I came up with a solution, but I ended up having to use system calls instead of the os/exec package's functions.

package main

import (
	"log"
	"os"
	"syscall"
	"unsafe"
)

var tty = "/dev/ttys001"
var cmd = "vim\n"

func main() {
	ttyFile, err := os.Open(tty)
	if err != nil {
		log.Fatalln(err)
	}
	defer ttyFile.Close()

	cbs, err := syscall.ByteSliceFromString(cmd)
	if err != nil {
		log.Fatalln(err)
	}

	var eno syscall.Errno
	for _, c := range cbs {
		_, _, eno = syscall.Syscall(syscall.SYS_IOCTL,
			ttyFile.Fd(),
			syscall.TIOCSTI,
			uintptr(unsafe.Pointer(&c)),
		)
		if eno != 0 {
			log.Fatalln(eno)
		}
	}
}

huangapple
  • 本文由 发表于 2016年9月6日 23:04:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/39352292.html
匿名

发表评论

匿名网友

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

确定