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

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

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

问题

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

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

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

非常感谢任何建议!

  1. package main
  2. import (
  3. "log"
  4. "os"
  5. "os/exec"
  6. )
  7. func main() {
  8. tty, err := os.OpenFile("/dev/ttys001", os.O_RDWR, os.ModePerm)
  9. if err != nil {
  10. log.Fatalln(err)
  11. }
  12. defer tty.Close()
  13. c := exec.Command("vim")
  14. c.Stdin = tty
  15. c.Stdout = tty
  16. c.Stderr = tty
  17. if err := c.Run(); err != nil {
  18. log.Fatalln(err)
  19. }
  20. }

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

  1. procAttr := &syscall.SysProcAttr{
  2. Setpgid: true,
  3. Ctty: int(tty.Fd()),
  4. Foreground: true,
  5. }
  6. 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!

  1. package main
  2. import (
  3. "log"
  4. "os"
  5. "os/exec"
  6. )
  7. func main() {
  8. tty, err := os.OpenFile("/dev/ttys001", os.O_RDWR, os.ModePerm)
  9. if err != nil {
  10. log.Fatalln(err)
  11. }
  12. defer tty.Close()
  13. c := exec.Command("vim")
  14. c.Stdin = tty
  15. c.Stdout = tty
  16. c.Stderr = tty
  17. if err := c.Run(); err != nil {
  18. log.Fatalln(err)
  19. }
  20. }

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.

  1. procAttr := &syscall.SysProcAttr{
  2. Setpgid: true,
  3. Ctty: int(tty.Fd()),
  4. Foreground: true,
  5. }
  6. c.SysProcAttr = procAttr

答案1

得分: 0

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

  1. package main
  2. import (
  3. "log"
  4. "os"
  5. "syscall"
  6. "unsafe"
  7. )
  8. var tty = "/dev/ttys001"
  9. var cmd = "vim\n"
  10. func main() {
  11. ttyFile, err := os.Open(tty)
  12. if err != nil {
  13. log.Fatalln(err)
  14. }
  15. defer ttyFile.Close()
  16. cbs, err := syscall.ByteSliceFromString(cmd)
  17. if err != nil {
  18. log.Fatalln(err)
  19. }
  20. var eno syscall.Errno
  21. for _, c := range cbs {
  22. _, _, eno = syscall.Syscall(syscall.SYS_IOCTL,
  23. ttyFile.Fd(),
  24. syscall.TIOCSTI,
  25. uintptr(unsafe.Pointer(&c)),
  26. )
  27. if eno != 0 {
  28. log.Fatalln(eno)
  29. }
  30. }
  31. }

希望对你有帮助!

英文:

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.

  1. package main
  2. import (
  3. "log"
  4. "os"
  5. "syscall"
  6. "unsafe"
  7. )
  8. var tty = "/dev/ttys001"
  9. var cmd = "vim\n"
  10. func main() {
  11. ttyFile, err := os.Open(tty)
  12. if err != nil {
  13. log.Fatalln(err)
  14. }
  15. defer ttyFile.Close()
  16. cbs, err := syscall.ByteSliceFromString(cmd)
  17. if err != nil {
  18. log.Fatalln(err)
  19. }
  20. var eno syscall.Errno
  21. for _, c := range cbs {
  22. _, _, eno = syscall.Syscall(syscall.SYS_IOCTL,
  23. ttyFile.Fd(),
  24. syscall.TIOCSTI,
  25. uintptr(unsafe.Pointer(&c)),
  26. )
  27. if eno != 0 {
  28. log.Fatalln(eno)
  29. }
  30. }
  31. }

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:

确定