3

这就是在 go 中通过系统调用获得(POSIX)终端大小的方式:

func getTermDim() (width, height int, err error) {
    var termDim [4]uint16
    if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(0), uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&termDim)), 0, 0, 0); err != 0 {
        return -1, -1, err
    }
    return int(termDim[1]), int(termDim[0]), nil
}

现在,同样的事情,用 os/exec 调用 stty:

func getTermDim() (width, height int, err error) {
        cmd := exec.Command("stty", "size")
        cmd.Stdin = os.Stdin
        var termDim []byte
        if termDim, err = cmd.Output(); err != nil {
                return
        }
        fmt.Sscan(string(termDim), &height, &width)
        return
}

在实践中,第一个解决方案可能会变得非常繁重且难以阅读,当一个人必须将终端置于原始模式、设置选项等时。当一个人习惯于 stty 时(例如在 shell 脚本中),第二个解决方案要容易得多!

所以我的问题是:使用第一个解决方案有什么好处?是速度?是不是我们不能依赖 stty 命令安装在宿主机上?还有什么我没有想到的吗?

简而言之,使用 stty 与系统调用的“风险”或“成本”是什么?

4

1 回答 1

2

关于风险:

  • stty: 如果该stty命令在$PATH. 或者,如果输入的stty命令$PATH不是您所期望的(这可能是一个安全问题)。或者,如果程序在占用空间极小的 Docker 容器中运行:您必须放入stty映像。
  • 系统调用:您的程序依赖于操作系统。只要您将该函数写入受构建标记保护的文件中,以确保构建在不受支持的操作系统上的编译时失败,就可以了。

关于性能,只需使用 package编写基准测试testing。但我已经可以告诉你,这exec.Command意味着多个系统调用的成本要比IOCTL/高得多TIOCGWINSZ

于 2020-12-01T09:44:02.280 回答