为什么这个exec.Command到另一个打开的tty不能正常工作

时间:2016-09-06 15:04:44

标签: macos vim go stdin tty

任何人都可以帮我弄清楚我在这里做错了什么。

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

运行下面的代码会在/ dev / ttys001的窗口中呈现vim,但实际上从该窗口输入stdin并没有正确注册。

非常感谢任何建议!

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:设备的不适当的ioctl。

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

1 个答案:

答案 0 :(得分: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)
        }
    }
}