web-dev-qa-db-ja.com

Goで端末サイズを取得する

Golangでttyサイズを取得するにはどうすればよいですか? stty sizeコマンドを実行してこれを実行しようとしていますが、コードを正しく作成できません。

package main

import (
  "os/exec"
  "fmt"
  "log"
)

func main() {
  out, err := exec.Command("stty", "size").Output()
  fmt.Printf("out: %#v\n", out)
  fmt.Printf("err: %#v\n", err)
  if err != nil {
    log.Fatal(err)
  }
}

出力:

out: []byte{}
err: &exec.ExitError{ProcessState:(*os.ProcessState)(0xc200066520)}
2013/05/16 02:35:57 exit status 1
exit status 1

これは、Goが現在のttyとは関係のないプロセスを生成し、それを使用しているためだと思います。サイズを取得するために、コマンドを現在の端末に関連付けるにはどうすればよいですか?

25
Ilia Sidorenko

子プロセスに親のstdinへのアクセスを許可すると機能します。

package main

import (
  "os/exec"
  "fmt"
  "log"
  "os"
)

func main() {
  cmd := exec.Command("stty", "size")
  cmd.Stdin = os.Stdin
  out, err := cmd.Output()
  fmt.Printf("out: %#v\n", string(out))
  fmt.Printf("err: %#v\n", err)
  if err != nil {
    log.Fatal(err)
  }
}

収量:

out: "36 118\n"
err: <nil>
17
lnmx

私は同様の問題で立ち往生していました。これが私が最終的に得たものです。

サブプロセスを使用しないため、状況によっては望ましい場合があります。

import (
    "syscall"
    "unsafe"
)

type winsize struct {
    Row    uint16
    Col    uint16
    Xpixel uint16
    Ypixel uint16
}

func getWidth() uint {
    ws := &winsize{}
    retCode, _, errno := syscall.Syscall(syscall.SYS_IOCTL,
        uintptr(syscall.Stdin),
        uintptr(syscall.TIOCGWINSZ),
        uintptr(unsafe.Pointer(ws)))

    if int(retCode) == -1 {
        panic(errno)
    }
    return uint(ws.Col)
}
24
deft_code

最近この問題に遭遇したので、新しい答えを追加したかっただけです。公式のsshパッケージ内にあるターミナルパッケージがあります https://godoc.org/golang.org/x/crypto/ssh/terminal

このパッケージは、端末のサイズを簡単に取得する方法を提供します。

width, height, err := terminal.GetSize(0)

0は、サイズを指定する端末のファイル記述子になります。 fdまたは現在の端末を取得するには、いつでもint(os.Stdin.Fd())を実行できます。

裏では、syscallを使用して、指定されたfdの端末サイズを取得します。

16
pech0rin

興味のある方は、これを簡単にするパッケージを作成しました。

https://github.com/wayneashleyberry/terminal-dimensions

package main

import (
    "fmt"

    terminal "github.com/wayneashleyberry/terminal-dimensions"
)

func main() {
    x, _ := terminal.Width()
    y, _ := terminal.Height()
    fmt.Printf("Terminal is %d wide and %d high", x, y)
}
6