因为有msys这样的项目,所以在Windows下我们也可以方便地使用bash(当然,有一些特性诸如process substitution在Windows下无法使用,因为Windows下没有Linux中的那种fifo)。因为有了bash这么好用的东西,我们很想把它和Windows下的vim,ipython这样的软件挂钩,Windows下的vim和ipython默认调用cmd.exe来执行外部程序。用过bash的人大概都会觉得cmd.exe实在是有点……不说别的,因为cmd.exe没有方便的command substitution(没有方便的,但是确实有,可以用for语句实现command substitution的功能,stackoverflow上有人专门讨论过这个问题),用起来感觉很受限制。而且经常在Windows和Linux两种平台上工作的人,很希望使用相同的方式完成类似的工作。
因为vim可以使用set shell和set shellcmdflag来修改vim调用的shell,因此今天我就试了试,在_vimrc中加入如下两行:
set shell=E:/Program/MinGW/msys/1.0/bin/sh.exe
set shellcmdflag=-c
就可以在vim中通过
:!command
来调用msys的sh.exe执行命令了。
大概故事就应该这样美好的结束了,其实不然。真正的故事才刚刚开始,而且实际上是一个伤心的故事。
因为vim会调用msys的bash来执行命令,所以我们就会以bash的方式来输入指令,问题产生了。例如,我们在vim中输入:
:%!awk 'BEGIN{print "abc"}'
期望abc会出现在编辑的文本之中,结果却什么也没有发生!难道输入的命令有问题吗?于是我们在Ubuntu下试了试:
明明很好使嘛。既然我们已经将vim的shell通过set shell设置成了msys的bash,为什么和Linux下的vim具有不同的行为呢?经过一番研究,终于发现了问题所在:
设置了shell和shellcmdflag之后,Windows的vim在执行指令时,会将输入的指令两端加上引号,如下:
而Windows在传递命令行参数时有这样一个特点:首先会以贪婪的方式匹配双引号对,然后将双引号对中间的双引号删除,引号删除后,对于awk而言,abc就不是一个字符串,而是变量名,这个变量没有初始化,awk就会默认把它初始化为空串,所以最终什么也没有发生。但是经过转义的双引号则会解释成双引号,所以如果想得到期望的结果,在Windows下就得输入:
:%!awk 'BEGIN{print \"abc\"}'
在引号前面加上\。效果如下:
这就导致了和Linux的vim操作上的差异,因为Linux下这种情况双引号不需要转义:
也就是说,虽然通过set shell使Windows下的vim可以调用bash来执行命令,但是仍然无法让Windows的vim和Linux的vim具有完全相同的调用外部命令的方式。
有个老程序员说过:非常相似,但有几分不同,其实是蛮危险的。所以最终我决定不修改shell,还是让vim使用默认的cmd.exe。
====
阅读(971) | 评论(0) | 转发(0) |