出于教育目的,我正在查看连接到终端的正在运行的 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
如果运行xterm
或rxvt
,它应该支持该转义序列。