熟悉Linux Shell环境的同学对“在当前工作目录下打开新的终端Tab”这一功能并不陌生吧,可是偏偏Mac OS X自带的Terminal工具对此功能的支持并不好,经常我们在打开新的Window或者Tab后还得沿着目录树一路重新找回去,很是不便,甚至我一度以为Mac OS X的重启电脑后自动恢复当前打开的App功能是不支持Terminal现场恢复的,直到我经过一整天的研究,终于找到了破解方法,在这里给大家做一个全面的分享。
I. 原理
其实有仔细研究过Mac OS X Terminal工具的同学想必也已经发现了,在Terminal > Preferences选项的General一栏中,实际上是有New windows/tabs open with: Same profile / Same Working Directory选项的,但是很多人可能会发现勾选了对应的选项后,实际上终端的行为却并不如自己所设想的那样工作,为什么?
这里就涉及到终端行为的工作原理了,实际上,这个选项只是激活了终端工具使用终端内部记录的当前工作目录来打开新Tab的功能,类似的功能还有在Terminal > Preferences > Profiles的Window/ Tab选项卡下勾选的Title: Working directory or document,你会发现在进入不同目录和打开不同文件过程中,实际上title有可能根本没有发生变化。为什么?原因是,Terminal工具内部记录的当前工作目录没有被更新。在类Unix系统中,Terminal工具天然是不知道当前工作目录是什么的,需要通过命令行来显示告知。个别同学会发现自己勾选了以上选项后Terminal的title或者新Tab功能是跟随当前工作目录变化的,原因是他们使用的是bash shell,而bash shell作为OS X的默认shell,其工作目录通知行为是预先写在了"etc/bashrc"或"~/.bash_profile"文件里的,如果你用的是其它shell,例如zsh或者csh,那么你就需要在自己的设置文件里打通这个Working directory的通知方式。那么如何打开呢?
II. 方法
其实方法很简单,Working directory的通知方法是通过调用OSC (Operating System Command)的方式来完成的,这一点在Terminal > Preferences > General选项下其实有用一行蓝色的字"Escape sequence..."来进行提醒。在zsh或者csh中,有一个内置的指令叫做precmd(),这个指令是在每一次用户输入其它命令执行前都会默认执行的,我们只需要把这个precmd()进行重写,修改为向终端传递Working directory的OSC指令就可以实现Terminal内部保存的工作目录更新功能了。具体来说,就是分别在csh的"/etc/csh.cshrc"和zsh的/etc/zshrc中输入以下内容
[source lang="bash"]
alias precmd 'printf "\033]7;file://${HOST}:$cwd\007"'
[/source]
以上命令的含义是,将系统内置的precmd以别名的方式重定向为一行printf命令,这个printf命令会通过终端打印的方式将OSC发送给终端,OSC命令的标准格式是\033]命令号;命令内容\007,其中\003和\007叫命令头和命令尾,在zsh中也可以写为\e和\a,如果有尝试失败的同学可以换成这2个试试,命令号7对应的就是Working directory,命令内容按协议要求必须是“file://”加“HOST名称”加“冒号:”再加上实际的Working directory。而${HOST}就是取环境变量HOST名称的意思,$cwd就是取当前工作目录变量的意思。
如果加入以上代码之后还是不能正常工作,可以尝试把单引号里面的部分在终端下直接输入并回车,观察是否可以正常工作,如果可以的话可能是precmd机制有问题,或是写入了错误的配置文件导致没有执行,否则可能是printf语句本身写错了。