简体   繁体   English

golang 中的终端:系统调用与 os/exec stty

[英]Terminal in golang: syscall vs os/exec stty

This is how one can get a (POSIX) terminal size with a syscall in go:这是通过 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
}

Now, the same thing, calling stty with os/exec:现在,同样的事情,用 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
}

In practice, the first solution can get pretty heavy and unreadable, when one has to put a terminal in raw mode, set up options etc. When one is used to stty (eg in shell scripts), the second solution is so much easier!在实践中,当必须将终端置于原始模式、设置选项等时,第一个解决方案可能会变得非常繁重且不可读。当一个人习惯于 stty 时(例如在 shell 脚本中),第二个解决方案就简单多了!

So my question is: what are the benefits of using the first solution?所以我的问题是:使用第一种解决方案有什么好处? It is speed?是速度? Is it that we cannot rely on the stty command to be installed on the host machine?是不是我们不能依赖stty命令安装到宿主机上? Anything else I don't think of?还有什么我没有想到的吗?

In a nutshell, what is the " risk " or the " cost " of using stty vs a syscall?简而言之,使用 stty 与系统调用的“风险”或“成本”是什么?

About the risk:关于风险:

  • stty : your program will not work correctly if the stty command is not available in $PATH . stty :如果$PATH没有stty命令,您的程序将无法正常运行。 Or if the stty command in $PATH is not the one you expect (it might be a security issue).或者,如果$PATHstty命令不是您所期望的(这可能是一个安全问题)。 Or if the program runs in a Docker container with a minimalist footprint: you'll have to put stty in the image.或者,如果程序在占用空间极小的 Docker 容器中运行:您必须将stty放入映像中。
  • syscall: your program is dependent on the OS.系统调用:您的程序依赖于操作系统。 It is fine as long as you write that function in file protected with build tags to ensure the build will fail at compile time on unsupported OS.只要您在受构建标记保护的文件中编写该函数以确保构建在不受支持的操作系统上编译时失败,就可以了。

About the performance, just write a benchmark using package testing .关于性能,只需使用 package testing编写一个基准testing But I can already tell you that exec.Command implies multiple syscalls much more costly than IOCTL / TIOCGWINSZ .但我已经可以告诉你exec.Command意味着多个系统调用比IOCTL / TIOCGWINSZ成本高得多。

In all likelihood, if stty exists on the box, the syscall is also present.很有可能,如果stty存在于盒子上,则系统调用也存在。 It's seems that it, and the argument TIOCGWINSZ , are a part of the SVR4 standard, which dates back about 20 years at this point and are widely implemented by Unixes everywhere, so it's unlikely you would need variant code for different OSes and an ioctl would be portable.似乎它和论点TIOCGWINSZ是 SVR4 标准的一部分,该标准可以追溯到大约 20 年前,并且在任何地方都被 Unix 广泛实施,因此您不太可能需要针对不同操作系统的变体代码,而 ioctl 会便携。

Running stty is more readable, certainly, but you're running a separate process, which comes with a cost.当然,运行 stty 更具可读性,但是您正在运行一个单独的进程,这是有代价的。

It's slower and considerably more expensive: the OS is starting a new process context and loading the binary;它更慢且成本更高:操作系统正在启动一个新的进程上下文并加载二进制文件; not only does your code make multiple syscalls, so does the process you run.不仅您的代码进行了多次系统调用,您运行的进程也是如此。

It also comes with a set of security concerns.它还伴随着一系列安全问题。 Perhaps the stty you found on your path is one the user put there, as just one example;也许您在路径上找到的 stty 是用户放在那里的,这只是一个例子; and if you embed a path, perhaps it's wrong for this specific OS).如果你嵌入了一个路径,对于这个特定的操作系统来说可能是错误的)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM