检测一个写入者是否为 tty 是可能的吗?

huangapple go评论81阅读模式
英文:

Is it possible to detect if a writer is tty or not?

问题

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

fmt.Println("3[1;34mHello World!3[0m")

我可以看到有颜色的文本,但如果我将输出导入到文件中,颜色是被保留的,这不是我想要的效果。

顺便说一下,这个问题大部分与Go无关,我只是想在我的Go程序中实现这种效果。

英文:

Bash has a 'magical behavior', if you type 'ls', usually you will get colorful output, but if you redirect the output to a file, the color codes are gone. How to achive this effect using Go. e.g. With the following statement:

fmt.Println("3[1;34mHello World!3[0m")

I can see the text in color, but if I pipe the output to a file, the color is preserved, which is NOT what I want.

BTW, this question is mostly not related to Go, I just want to achive the effect in my go program.

答案1

得分: 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;
}

你可以在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("3[1;34mHello World!3[0m")
        }
}
英文:

> Bash has a 'magical behavior', if you type 'ls', usually you will
get colorful output, but if you redirect the output to a file, the
color codes are gone.

It's not Bash feature, it's ls feature. It calls
isatty()
to check if stdout file descriptor refers to a terminal. In musl libc
isatty is implemented like that:

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;
}

You can use the same method in 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("3[1;34mHello World!3[0m")
        }
}

答案2

得分: 3

我只是复制了@ptx的评论作为回答,这是更标准的答案:

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

这样做是为了提高可见性,因为这个答案是可移植的,不会增加外部依赖。

package main

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

func main() {
	if term.IsTerminal(int(os.Stdout.Fd())) {
		// 当我们连接到tty时执行某些操作
	} else {
		// 当我们没有连接时执行某些操作
	}
}
英文:

I'm just answering by copying @ptx comment, which is the more canonical answer:

> A better approach is to use term.IsTerminal from x/term. It works on windows and is maintained by the golang team

This is to raise visibility, as this answer is portable and doesn't add an external dependency.

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
	}
}

答案3

得分: 0

如果你只是查看日志文件,并且不希望保留颜色,因为这会使日志变得不易读,请注意以下命令:

less -r logfile
more -r logfile
multitail -cT ANSI logfile

这些命令将显示 ANSI 颜色。

还有一个 vim 插件可以实现相同的效果:https://github.com/powerman/vim-plugin-AnsiEsc

对于某些用例而言,这可能是一个比升级应用程序以检测输出是否连接到 tty 更简单的解决方案。

英文:

If you are just viewing a log file and don't want colors being preserved because it makes logs less readable, note that

less -r logfile
more -r logfile
multitail -cT ANSI logfile

will make these commands display ANSI colors.

There is also a vim plugin which does the same: https://github.com/powerman/vim-plugin-AnsiEsc

For some use cases this could be a simpler solution than upgrading an app to detect whether an output is attached to a tty.

huangapple
  • 本文由 发表于 2021年8月23日 16:42:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/68889637.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定