【发布时间】:2018-12-01 19:55:55
【问题描述】:
这是如何通过 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 与系统调用的“风险”或“成本”是什么?
【问题讨论】:
-
IMO 系统调用版本更加清晰,唯一的改进是我将它包装成一个通用函数,该函数将模拟
ioctl接口(当然是 Go 风格),然后是 @ 987654326@ 会打电话给那个。 -
另一种方法是不要重新发明轮子,而是抓住golang.org/x/crypto/ssh/terminal 或github.com/nsf/termbox-go 来利用他们使用终端的能力。
-
我们对更清楚的事情的分歧应该来自这样一个事实,我有点知道
stty做了什么,因此改为调用它或做它应该做的事情直接是只是粗鲁。对于那些习惯使用 shell 脚本的人来说,调用stty应该更合乎逻辑:-) -
感谢您的意见,kostix。看来这最终取决于个人喜好。
-
我有另一个案例 pro 系统调用:如果你的程序的标准输出没有连接到 TTY,系统调用允许更明智的错误处理,否则你必须解析
stty的输出并依靠它在不同的可能平台上保持稳定(我对此表示怀疑)。
标签: go terminal system-calls stty