我正在查看连接到终端的正在运行的 bash 进程的 strace 输出,用于教育目的。
我的 bash 进程的 PID 为 2883。
我输入
[OP@localhost ~]$ strace -e trace=openat,read,write,fork,vfork,clone,execve -p 2883 2> bash.strace
进入终端。然后我进入 bash 进程,并进行以下交互:
[OP@localhost ~]$ ls
看看输出,我明白了
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
...
我对最后两行感到困惑。 bash 似乎正在尝试编写两个 shell 提示符?这里发生了什么?
答案1
该<ESC>]0;
序列(由 strace 显示\33]0;
)是设置终端窗口标题的转义序列。它以 BEL 字符 ( ) 结尾\7
,因此第一个write
设置窗口标题。第二个打印实际的提示。请注意,即使除了转义序列之外,它们也不完全相同。提示有周围,[..]
而窗口标题没有。
我们还可以看到第一次写入到 stdout(fd 1,第一个参数write()
),第二次写入到 stderr。 Bash 将提示打印到 stderr,因此第一个写入来自其他地方。可能是在某个地方PROMPT_COMMAND
,就像 Debian 的 Bash 默认启动脚本中的那个一样。里面有这样的东西:
case "$TERM" in
xterm*|rxvt*)
PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME}: ${PWD}\007"'
;;
*)
;;
esac
它设置PROMPT_COMMAND
if runningxterm
或rxvt
,它应该支持该转义序列。