Bash 尝试编写两个 shell 提示?

ext*_*xe5 11 bash tty strace

出于教育目的,我正在查看连接到终端的正在运行的 bash 进程的 strace 输出。

我的 bash 进程的 PID 为 2883。

我打字

[OP@localhost ~]$ strace -e trace=openat,read,write,fork,vfork,clone,execve -p 2883 2> bash.strace
Run Code Online (Sandbox Code Playgroud)

进入一个终端。然后我进入我的 bash 进程,并进行以下交互:

[OP@localhost ~]$ ls
Run Code Online (Sandbox Code Playgroud)

查看输出,我看到

strace: Process 2883 attached
read(0, "l", 1)                         = 1
write(2, "l", 1)                        = 1
read(0, "s", 1)                         = 1
write(2, "s", 1)                        = 1
read(0, "\r", 1)                        = 1
write(2, "\n", 1)                       = 1
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7fec6b1d8e50) = 3917
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=3917, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
write(1, "\33]0;OP@localhost:~\7", 23) = 23
write(2, "[OP@localhost ~]$ ", 22)  = 22
...
Run Code Online (Sandbox Code Playgroud)

我对最后两行感到困惑。看来 bash 正在尝试编写两个 shell 提示?这里发生了什么?

ilk*_*chu 24

<ESC>]0;序列(示出为\33]0;通过strace的)是转义序列来设置终端窗口标题。它以 BEL 字符 ( \7)结尾,因此第一个write设置窗口标题。第二个打印实际提示。请注意,即使除了转义序列之外,它们也不完全相同。提示有周围,[..]而窗口标题没有。

我们还可以看到第一次写入到标准输出(fd 1,第一个参数到write()),第二次写入到标准错误。Bash 将提示打印到 stderr,因此第一次写入来自其他地方。某个地方可能是PROMPT_COMMAND,就像 Debian 的 Bash 默认启动脚本中的那个一样。里面有这样的东西:

case "$TERM" in
xterm*|rxvt*)
    PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME}: ${PWD}\007"'
    ;;
*)
    ;;
esac
Run Code Online (Sandbox Code Playgroud)

它设置PROMPT_COMMAND如果运行xtermrxvt,它应该支持该转义序列。