是否可以检测 writer 是否为 tty?

xrf*_*ang 9 console colors go tty

Bash 有一个“神奇的行为”,如果你输入“ls”,通常你会得到彩色的输出,但是如果你将输出重定向到一个文件,颜色代码就会消失。如何使用Go实现这种效果。例如使用以下语句:

fmt.Println("\033[1;34mHello World!\033[0m")
Run Code Online (Sandbox Code Playgroud)

我可以看到彩色文本,但如果我将输出通过管道传输到文件,颜色将被保留,这不是我想要的。

顺便说一句,这个问题大多与Go无关,我只是想在我的Go程序中达到效果。

Jon*_*tte 9

我只是通过复制 @ptx 评论来回答,这是更规范的答案:

更好的方法是使用x/term中的 term.IsTerminal 。它适用于 Windows,由 golang 团队维护

这是为了提高可见性,因为这个答案是可移植的并且不会添加外部依赖项。

package main

import (
    "os"
    "golang.org/x/term"
)

func main() {
    if term.IsTerminal(int(os.Stdout.Fd())) {
        // do stuff when we are attached to a tty
    } else {
        // do stuff when we are not attached
    }
}
Run Code Online (Sandbox Code Playgroud)


Ark*_*zyk 6

Bash 有一个“神奇的行为”,如果你输入“ls”,通常你会得到彩色的输出,但是如果你将输出重定向到一个文件,颜色代码就会消失。

这不是 Bash 功能,而是 ls 功能。它调用 isatty() 来检查 stdout 文件描述符是否引用终端。在 musl libc isatty 中是这样实现的:

int isatty(int fd)
{
        struct winsize wsz;
        unsigned long r = syscall(SYS_ioctl, fd, TIOCGWINSZ, &wsz);
        if (r == 0) return 1;
        if (errno != EBADF) errno = ENOTTY;
        return 0;
}
Run Code Online (Sandbox Code Playgroud)

您可以在 Go 中使用相同的方法:

package main

import (
        "fmt"
        "os"

        "golang.org/x/sys/unix"
)

func main() {
        _, err := unix.IoctlGetWinsize(int(os.Stdout.Fd()), unix.TIOCGWINSZ)
        if err != nil {
                fmt.Println("Hello World")
        } else {
                fmt.Println("\033[1;34mHello World!\033[0m")
        }
}
Run Code Online (Sandbox Code Playgroud)

  • 更好的方法是使用 [x/term](https://pkg.go.dev/golang.org/x/term#IsTerminal) 中的 `term.IsTerminal`。它适用于 Windows,由 golang 团队维护 (2认同)