知道了也没什么用的小知识:终端标题与转义序列

起因

事情的起因是这样的,我在 archlinux (以下简称 arch) 下的端模拟器(以下简称终端)使用 set -x 来调试,发现每次按回车都会一条类似下面这样的输出:

++ printf '\033]0;%s@%s:%s\007' nanpuyue arch '~'

然后我手动执行了这条命令也看不到任何输出和变化,着实令人费解。

OSC 转义序列

一番查找过后在 /etc/bash.bashrc 中找到了源头:

case ${TERM} in
  xterm*|rxvt*|Eterm|aterm|kterm|gnome*)
    PROMPT_COMMAND=${PROMPT_COMMAND:+$PROMPT_COMMAND; }'printf "\033]0;%s@%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/\~}"'

    ;;
  screen*)
    PROMPT_COMMAND=${PROMPT_COMMAND:+$PROMPT_COMMAND; }'printf "\033_%s@%s:%s\033\\" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/\~}"'
    ;;
esac

原来这条命令是输出特殊的转义序列,用来更改终端的标题,相关的信息可以查看这篇文档 XTerm Control Sequences

其中一个表格有相关内容:

    OSC 0 ST      -    yes    yes    set window and icon title
    OSC 1 ST      -    yes    yes    set icon label
    OSC 2 ST      -    yes    yes    set window title
    OSC 3 ST      -    n/a    yes    set X server property
    OSC I ST     yes   yes    yes    set icon to file
    OSC l ST     yes   yes    yes    set window title
    OSC L ST     yes   yes    yes    set icon label

总结起来就是我们可以用 \033]0;title\007 来设置终端标题,其中\033 也可以用 \e 代替,\007 可以用 \a 代替,\033]0; 换成 \033];2 也是可以的。

就像上面提到的文档中描述的一样,他们管这种转移序列叫 OSC (Operating System Commands) 转义序列。

deepin-terminal

大部分终端都是支持这种转义序列的,发行版们也一般会把这样的转移序列默认配置到 PS1 变量或 PROMPT_COMMAND 变量中,用来在终端标题显示一些信息。两者的区别在于 PS1 变量一条命令结束接受下一条命令的输入之前由 shell 直接显示出来的,而 PROMPT_COMMAND 中存储的是可以执行的命令,由 shell 在显示 PS1 之前执行。

我测试了 tilix 和 gnome-terminal,都是支持的,唯独我日常使用的 deepin-terminal 不支持,这也是我一开始手动执行命令那条 printf 命令没有效果的原因。

然后我扒了一下 deepin-terminal 的源码,原来之前老王自己实现了一套逻辑,默认情况下会将标题显示为当前目录名。代码中当 vte (deepin-terminal 也是基于 vte 的) 的 window_title_changed 信号会触发 deepin-terminal 更新终端标签的标题,上面提到的转移序列能都产生 window_title_changed 信号,仅仅是 shell 中的命令退出而不输出上述转移序列的话是不会产生 window_title_changed 信号的。

所以我把终端标题更新这里的逻辑改成了与 gnome-terminal 一样,遵从 OSC 转义序列设置的标题,如果用户想要自定义终端标题的更新方式,应该修改 PS1PROMPT_COMMAND 变量。

提交见:5feb41272249fb10feccb5fa4d9c848155bbcbbf

标签: Linux, Bash, Shell, Terminal

已有 2 条评论

  1. 诶。。。乔帮主也用Arch了?

添加新评论