作为我在我的ThinkPad T41上设置了NetBSD,我发现自己想要一小块功能:
我希望我的XTerm窗口标题反映了在终端中运行的shell的当前状态。作为工作目录和运行进程。
一件简单的东西,对了吗?所以我想也是如此。但问题比它看起来更复杂。
解决方案i' ve终于解决了shell [1]源的正常修改,以及与shell通信的自定义程序,不断更新相关的Xterm窗口的标题[2]。要了解为什么最好的解决方案,我们需要通过并解雇替代方案。
有两种方法可以改变终端窗口的标题:通过X11或终端控制代码。
由于它们被直接发送到终端(仿真器),因此没有意外地影响错误窗口的风险。
它们可以由shell' s内置echo命令发送,从而减少运行外部命令的延迟。
如果您搜索互联网以获取设置终端Titlevo当前工作目录的方法,请' ll沿着以下行找到许多建议:
这发送了CSI 2; < title> Bel控制序列到终端的每个提示,指示它设置窗口标题[3]。
并非所有终端仿真器都支持此控制序列..例如,SBSD' S WSCONS完全破碎。
这些点都不是他们自己的大问题。您可以检查$术语以识别WSCons.You可以告诉屏幕转发控制excomby添加ESC P前缀ASP \后缀。
当您尝试组合它们时,问题开始。如果您告诉屏幕转发控制序列,它可能会将其转发给WScons.This将不会被屏幕会话在除WSCons其他地方启动屏幕会话。
例如,我正在Xterm中的屏幕会话中撰写了JWM Window Manager [4]的叉子.I意识到我需要重新启动X才能尝试我的更改,因此我从屏幕会话中分离并退出X. 。
回到WSCONS中,我意识到我仍然需要编译我的更改。所以我重新附加到屏幕会话并输入make.everything直到我的shell' s迅速展示了。很多,键入的人物Weren&#39 ;在屏幕上显示,任何似乎都有任何方法来解决它。
在我的shrc中,我确保了$ xterm_shell是setBefore我发送了控制序列,但由于屏幕会话在xterm中启动,即使我已附加到WSCons中的会话,也是如此,因此Xterm_Shell。
拒绝那里有任何明显的方法。对解决方案的最接近的东西是终端的一定的控制序列,它要求它为其辅助设备属性。这些对于不同的终端将是不同的.I don& #39; t知道他们是否保证是独一无二的,但它们很好地与另一个终端区分开。
与另一个问题相结合,直到现在。ve ve ide。直到现在。我说你可以告诉屏幕转发控制序列父终端。威尔,它让你不想做这个&#39 ;重新在GNU屏幕中。
我对这些问题的解决方案称为Subetitle [5]。它是一个c程序,它试图弄清楚终端基于其辅助设备属性的身份。如果识别的终端被列入黑名单(WSCons),则会发送。否则,它会发送设置终端标题的控制序列。但是忘记了:如果终端被识别为GNU屏幕,则它还发送特殊转发控制序列。
然而,尽管如此,我没有完全满足。只有停用一个黑客,而且因为它需要在每次提示时刻到儿童进程,这有点慢。
在翻盖方上,当$术语设置为屏幕时,可以更好地使用它,并使用传统方法否则使用传统方法。若要使用它,只是它支持的GNU屏幕的事实非常棒,我可能会留下这是这个故事的下一部分的IT Weren' t。
禁止上述意外的并发症,将终端标题设置为当前工作目录很容易。它更难以设置当前运行的程序的终端TITLETO。
第一个问题是术语。目前正在运行的程序均匀意味着什么可能不会意味着贝壳本身,这是问题的明显答案;一个可能意味着在壳体内运行的程序。
问题是,shell可以立即运行许多程序。查看以下过程树:
269 TTYE0 S 0:01.51 XTTTEM 977 TTYP0 SS 0:00.04 - KSH 808 TTYP0 T 0:00.02 | - VI Makefile 1204 TTYP0 T 0:01.42 | - VI A-Simpt-intern.em 9465 TTYP0 0 + 0:00.01 ` - vi ps -d
XTerm正在运行KSH,它同时运行三个进程。可以说哪个是"正确的"目前正在运行的过程?
一个解决方案是根据当前运行的一个解决方案。以下Shell脚本确实如此.Given一个PID,它打印了相应过程的PID'最小的孙子:
ps -do pid,eTime,comm -k eTime $ opt | pid = $ 1 perl -lane' if(/ ^ * $ env {pid} / .1){next if / ^ * $ env {pid} /;持续的,如果不是/ [|` - ] /; $ t = 0; $ i = 0; $ t + = $ _ *(60 ** $ i ++)用于反向拆分/:/,$ f [1];打印" $ t $ _"如果$ t> 2; }' |排序-n | HEAD -1 | CUT -D \ -F2
可以想象,可以通过每个都可以检查脚本的输出,所以经常设置相应的XTerm窗口的标题。
这个天真解决方案的问题是,过程中的年龄' t反映了它当前是否在shell中处于活动状态。此信息的唯一来源是shell本身。
因此,也许shell可以设置窗口标题,无论它开始还是继续一个过程。在流行的贝壳上环顾四周,景观相当干燥。
Z shell是唯一适当支持类似的shell。它提供了PRODMD和PREExec函数[6]:
可以在BASH中模拟PREEXEC,但它最多是一个黑客:如果在BASH执行的每个命令之前,将触发特殊调试信号处理程序。
所有这些都是真实的,称重问题。如果只有更好的方法可以与我选择的壳牌一起使用,这是一个更好的方法。
korn shell是开源的,我开始尝试修改它。我想在shell本身中实现以下功能:
不幸的是,我跑到了一个大问题:我找不到任何方法让shell自身归咎于终端控制序列,而不破坏东西。我' d得到它工作直到我尝试运行ed,在哪一点键入字符将停止显示。
底层问题是终端难以使用。不同的终端支持不同的控制序列,并且终端的当前状态很难得到推理。
所以我把所有以前的工作都辞载了,开始思考一个更可靠的解决方案可能看起来更加可靠的解决方案。在睡眠中,睡得很好,我想出了这个:
创建从命名管道读取的程序,并通过X11 API设置相应的XTerm窗口的Window标题。
#!/ bin / shrm /var/war/war/session 2> / dev / nullmkfifo /var/$$ .sessionxterm -e Ksh -w /var/$$$。PID = $!xdotool search --sync - -PID $!CAT / VAR / $ SESSION |读Ln;案例" $ ln"在cwd *)cwd = $ {ln#cwd} xdotool --pid $! set_window --name" $ cwd" ;; cmd *)cmd = $ {ln#cmd} xdotool --pid $! set_window --name" $ cmd($ cwd)" ;; *)xdotool - pid $! set_window --name" $ cwd" ;; Esacdone.
该脚本创建一个命名管道并在xterm中启动ksh,告诉它从命名的pipe.then读取,它等待与启动的Xterm进程的PID关联的窗口出现。窗口出现,脚本开始读取读取命名为管道,在每行读取时更新标题。
这个初始shell脚本没有工作,因为xdotool在设置窗口标题时相当不可靠。但是我知道这是可能的,因为我写了一个小的C程序,自己可以设置窗口标题。
我修补了[1] NetBSD' s Ksh支持一个名为-W的新选项,它期望提供了文件的名称。如果提供的,shell将打开forth的文件,然后,只要发出交互式命令,提示是编写的shell的CWD已更新,单行将写入文件。行具有以下格式:
第二个组件TTTERM [2]是什么都在一起包装.UPON执行,它在文件系统上创建一个命名管道,由TTTTM'自己的PID。然后,它立即叉。
同时,父进程开始查找属于子进程的PID的窗口。找到这样的窗口,它开始从命名管道读取。
对于每行读取,它将找到的窗口的标题设置为以下规则:
例如,它将标题设置为启动时的CWD,这可能是您的主目录,因此它将其设置为〜.then,当您运行VI Todo时,它将标题设置为VI Todo(〜)。最后,当您退出时VI,它将标题设置为〜。
总之,我跳过了世界各地的解决方案,以非常简单的问题。所以解决方案也很简单。
它只有一个问题:它没有与GNU屏幕一起工作。当它不可能使其工作,它需要很多努力。在此期间,I' m很高兴回落在SafeTlewhen $术语时被设置为屏幕:
窗口标题对我来说特别珍惜,因为我用它们来弄清楚当前工作目录,它是一个名为dwim [7]的脚本,它在Unix上模拟了计划9管道系统.it是一个非常有用的脚本系统,我可以' t live没有。
最后,我希望这个页面可以作为那些一直在寻找与me的答案的资源。我在这一主题中度过了非常大量的时间,所以一定要给我发一个 邮件[8]如果有你的东西'重新想起。