如何确定终端的背景颜色?

37

我想知道是否有办法确定终端的背景颜色?

在我的情况下,使用的是gnome-terminal。
这可能很重要,因为完全由终端应用程序绘制其窗口的背景,这甚至可能不是纯色。

6个回答

25

针对此问题,有一个xterm控制序列

\e]11;?\a

\e\a分别是ESC和BEL字符。)
Xterm兼容终端应该用相同的序列回复,将问号替换为X11颜色名称,例如rgb:0000/0000/0000表示黑色。

14
关于如何利用这个工具的一些信息将是一个很好的补充。例如,一个打印单词并根据shell的背景颜色以不同前景颜色显示的shell脚本片段。 - ELLIOTTCABLE
(我怀疑这只会获取文本的背景颜色,如果一个关闭它。而不是实际终端窗口的背景颜色,我认为在rxvt之外仍然无法获得。) - ELLIOTTCABLE
3
在Mac 10.10.4中,这个(和@blueyed类似的回答)在苹果终端(被标识为xterm-color)中似乎无法工作,但在常规xterm中可以工作。 - TextGeek
3
确认此解决方案在Mac OS-X BigSur上的iTerm2和Terminal都有效:❯ printf "\e]11;?\a"会产生^[]11;rgb:0000/0000/0000^G%,在iTerm2中则会产生^[]11;rgb:0000/0000/0000^G。但是我无法捕获这个输出并在shell脚本中使用if语句。这是否有可能? - Konstantin Gredeskoul
@Konstantin Gredeskoul - 很晚才回复,但是@blueeyed的答案可以捕获输出。我需要增加MacOS终端(Big Sur)的sleep超时时间。 - devstuff
显示剩余2条评论

20
我想到了以下内容:
#!/bin/sh
#
# Query a property from the terminal, e.g. background color.
#
# XTerm Operating System Commands
#     "ESC ] Ps;Pt ST"

oldstty=$(stty -g)

# What to query?
# 11: text background
Ps=${1:-11}

stty raw -echo min 0 time 0
# stty raw -echo min 0 time 1
printf "\033]$Ps;?\033\\"
# xterm needs the sleep (or "time 1", but that is 1/10th second).
sleep 0.00000001
read -r answer
# echo $answer | cat -A
result=${answer#*;}
stty $oldstty
# Remove escape at the end.
echo $result | sed 's/[^rgb:0-9a-f/]\+$//'

源代码/仓库/Gist: https://gist.github.com/blueyed/c8470c2aad3381c33ea3


1
这似乎无法与gnome-terminal 3.6.2一起使用。 - aramadia
适用于gnome-terminal 3.36.1,但需要更长的睡眠时间,例如 sleep 0.01 - fzbd
还有一个转义序列打印在开头,所以我用 sed 's/.*\(rgb:[0-9a-f/]*\).*/\1/' 进行过滤。 - fzbd
@blueyed,有没有办法用ANSI RGB颜色替换XTERM RGB颜色? - Oo'-
在Konsole中运行良好,但在Kitty中非常不稳定 :/ 编辑:将睡眠时间提高到0.01也可以使其在那里可靠。 - xeruf

5
一些链接:

例如,来自Neovim问题2764的相关片段:

/*
 * Return "dark" or "light" depending on the kind of terminal.
 * This is just guessing!  Recognized are:
 * "linux"         Linux console
 * "screen.linux"   Linux console with screen
 * "cygwin"        Cygwin shell
 * "putty"         Putty program
 * We also check the COLORFGBG environment variable, which is set by
 * rxvt and derivatives. This variable contains either two or three
 * values separated by semicolons; we want the last value in either
 * case. If this value is 0-6 or 8, our background is dark.
 */
static char_u *term_bg_default(void)
{
  char_u      *p;

  if (STRCMP(T_NAME, "linux") == 0
      || STRCMP(T_NAME, "screen.linux") == 0
      || STRCMP(T_NAME, "cygwin") == 0
      || STRCMP(T_NAME, "putty") == 0
      || ((p = (char_u *)os_getenv("COLORFGBG")) != NULL
          && (p = vim_strrchr(p, ';')) != NULL
          && ((p[1] >= '0' && p[1] <= '6') || p[1] == '8')
          && p[2] == NUL))
    return (char_u *)"dark";
  return (char_u *)"light";
}

关于COLORFGBG环境变量,来自Gnome BugZilla 733423
在我试过的很多Linux终端中,只有urxvt和konsole设置了它(不设置的有:xterm、st、terminology、pterm)。Konsole和Urxvt使用不同的语法和语义,例如对我来说,konsole将其设置为“0;15”(即使我使用“黑色底白色字”颜色方案 - 那么为什么不是“默认”而是“15”?),而我的urxvt将其设置为“0;default;15”(实际上是黑色底白色字 - 但为什么有三个字段?)。因此,在这两种终端中,值都不符合您的规范。
这是我正在使用的一些自己的代码(通过):
def is_dark_terminal_background():
    """
    :return: Whether we have a dark Terminal background color, or None if unknown.
        We currently just check the env var COLORFGBG,
        which some terminals define like "<foreground-color>:<background-color>",
        and if <background-color> in {0,1,2,3,4,5,6,8}, then we have some dark background.
        There are many other complex heuristics we could do here, which work in some cases but not in others.
        See e.g. `here <https://dev59.com/GXE95IYBdhLWcg3wAo9U
        But instead of adding more heuristics, we think that explicitly setting COLORFGBG would be the best thing,
        in case it's not like you want it.
    :rtype: bool|None
    """
    if os.environ.get("COLORFGBG", None):
        parts = os.environ["COLORFGBG"].split(";")
        try:
            last_number = int(parts[-1])
            if 0 <= last_number <= 6 or last_number == 8:
                return True
            else:
                return False
        except ValueError:  # not an integer?
            pass
    return None  # unknown (and bool(None) == False, i.e. expect light by default)

感谢关于$COLORFGBG的提示。它至少在iTerm2上有效。这是获取iTerm2会话背景颜色的非常直接的方法。+1 - hraban

3

正如其他人所提到的,您可以使用 OSC 11 ? 查询终端(尽管支持程度有所不同)。

在 bash 和 gnome-terminal 中:

read -rs -d \\ -p $'\e]11;?\e\\' BG
echo "$BG" | xxd

00000000: 1b5d 3131 3b72 6762 3a30 3030 302f 3262  .]11;rgb:0000/2b
00000010: 3262 2f33 3633 361b 0a                   2b/3636..

请注意,Bash在这方面有一些不错的功能(例如read -s禁用回显,$''字符串用于转义代码),但不幸的是它会吞掉最后一个反斜杠。

1

-1

我的意思是确定背景颜色。不是用转义码打印字符的颜色,而是窗口本身的颜色。不过文章写得很好 :) - Romuald Brunet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接