
- 帖子
- 23
- 积分
- 57
- 技术
- 11
- 捐助
- 0
- 注册时间
- 2011-10-19
|
本帖最后由 leeonix 于 2011-10-19 20:42 编辑
By LeeoNix 2011年10月19日
2011年10月8日,C语言的作者。Dennis Ritchie去世了。看着这个消息我发呆了很久。可以说,你看我这篇文章的时候,面前所有的“虚拟”的东西,都与这位大师有关。他是真正的大师,那天我决定写1000行C或者其他的代码。那天我写了大概500行的C代码,写了一个生成批处理的Python脚本。纪念这位大师,作为一个程序员,除了写更精细的代码,没有别方式去纪念他。
和朋友聊天,他说,既然你用到了Python,就全用就是了。干吗还要生成批处理呢?我的回答,批处理的环境变量依赖是很方便的,而且我还要用vc编译3个vc工程,一个Delphi工程。还要用sed处理合适的文本输出。用Python组合这些操作就非常麻烦了。
写完这些之后,我就想写一篇文章,以前,一个后辈说从这里学了不少东西,今天我就注册个号发一篇文章回馈一下。其目的是,批处理该用什么,以及什么时候该用到批处理。
1、批处理的定位。
所谓的Windows批处理。实际上是CLI(command-line interface,命令行界面)的一种,具体见(http://baike.baidu.com/view/160512.htm)。而CLI区别与用户图形界面,其优势是,可以根据各种命令组装成批量执行的命令。
批处理其优势就是Windows提供的原生工具。这一点优势就足够说明为什么在Windows下使用批处理,多的优势根本不用多说。其欠缺的也很明显,缺乏模块化的语句,缺乏对数字和逻辑类型操作的方法,条件分支和循环语句都很弱小,字符串操作也很弱。
批处理依赖的环境是一个开放式的大环境,面向整个系统。换句话说是其实是“不安全”的,比如我用call默认调用另外一个批处理,实际上你可以在主题批处理上用到被call的批处理里面的变量名。打个不恰当的比方说,就像一个大厂房,倘若你和你的异性伴侣在OOXX,实际上路过想看的人都是可以看得到的。虽然是可以用setlocal...但其优势又是因为是开放式的,而且可以根据环境变量去获取,各种东西随便用,在轻量级调用方面,就省却了很多麻烦。
如果有工厂经验的人,会理解我说的话。其实批处理最好的定位,就是一个大的方便的组装车间。而不要特别去想成为加工车间。强求只会陷入误区。
2、关键的操作符。
Unix最初的创建者中,有位大师叫Doug MclIroy。他低调的隐藏在Ken Thompson和Dennis Ritchie之下。并不为所有程序员所知。他为Unix发明了管道以及使用管道操作符"|",而这点被借鉴到了Windows系统。
看到这里,请记住管道以及管道的发明者,Doug MclIroy。
管道的意义非常简单:上一个指令的输出作为下一个指令的输入。搜索管道的介绍,你会看到管道的基本指令。ls -l | more。而在Windows下,其实这个也是很有意义的指令。比如C:\Windows\System32这个文件夹下,有非常非常多的文件。一次是看不完的,那就输入C:\WINDOWS\system32>dir | more。dir显示不全的交给more显示就可以了。
举个我实际的例子,我写的Lua脚本,有个debug库,我为了提高效率,在给别人的时候会把这个有关debug的信息处理掉。只要利用sed把根据关键字注释掉,然后扔给lua编译器便以为byte code就可了。listfile是我预先写好的或者用>操作符生成的临时文件。
代码:
for /f %%i in (%listfile%) do (
sed.exe "s/debugstr\./--/g" %%i | luac.exe -o %TEMP%\script\%%i -s -
)
有关管道的介绍,可以从网上找到很多。
输入操作符,输出操作符。< > << >>这也是借鉴的Unix系统的操作符。只能用于标准输入输出进行操作。而例如stderr输出的,则不会被使用。具体在下面会有例子。
3、命令行工具。
使用批处理,就与命令行工具息息相关。而cmd.exe本身提供的指令非常有限,参数也很有限。所以命令行工具是主要补充。其实Windows本身提供的命令行工具,打开C:\WINDOWS\system32,会看到很多普通图标的工具,也可以从网上查到大概的功能。但很多提供的功能很有限用起来也比较无奈,比如findstr,还不如下载一个grep用。而自己用编译类语言写的工具,或者用脚本语言写的,只要符合标准输入输出流的,都可以作为工具集使用。
Unix工具的易用性是毋庸置疑的,在Windows上使用,好几个实现版本。
gow这个是比较全也比较轻量的,是整理的gnu工程再发布的。
http://wiki.github.com/bmatzelle/gow/
gnuwin32是gnu官方提供的,文档比较全。更新比较方便,但很多可能你不需要的东西在里面。
http://gnuwin32.sourceforge.net/
UnxUtils也是一个整理的工具集。
http://sourceforge.net/projects/unxutils/
个人推荐gow。
使用unix工具集,会有几个选择。面临很多的选择,dir还是ls?findstr还是grep?del还是rm?copy还是cp?就速度上,Windows提供的当然快很多,但作为使用管道的工具来说,还是后面的工具更合适。
但是很多冲突需要注意,举个例子:find命令,被windows定位为搜索字符串,但在Unix工具里面是搜索文件的,而find命令搜索文件,是很方便的,结合xargs可以作很多事情。类似的冲突还是比较多的。而gnu提供的find命令是很好用的。扔掉windows带的那个find.exe,从C:\Windows\System32下可以安心删除它。换成grep。
4、正则表达式。
文字处理方面,正则表达式是必须的,但在批处理上用大多数的正则表达式是无意义的。
Unix最初的创建者中,还有有位大师叫Brain Kernighan。他在《程序设计实践》里介绍了一个极简单的grep实现代码。只提供了四个操作符"." "*" "^" "$",这四个字符,体现了一个好的“记法”可以增长人的工作效率。在书里面提到了,就这四个操作符就可随意解决大部分问题。而另一本书《代码之美》的第一篇也是对这个实现的一个介绍。《程序设计实践》里,大师说了:好的记法只有与人们的工程经验相结合,才能产生自然而有效的工具。
而为什么要使用这些字符?接触批处理的,都会有一个概念,叫“通配符”。比如dir *.dll这样的。*代表了“所有”。而*号,就是dir这个工具提供的“记法”,让用户明白“所有”这个概念。仅仅使用dir这样的工具提供的是远远不够的。所以才要使用正则表达式。在批处理里面使用简单的正则表达式足够,如上面提到的4个。而利用grep这样的工具过滤,会更容易让人理解。而上面的dir *.dll也可以用dir | grep "\.dll$"来做到同样的功能,但过滤了很多无用的信息方便下一步操作。
进一步的例子:dir | grep "\.dll$" | awk "{ print $1, $3 }" 会输出列表内dll文件的日期和大小。
利用正则表达式可以让你找到你想要的。
5、纯文本。
Eric Raymond,在《Unix编程艺术》里,多次提到了纯文本的威力。缺乏数据结构支持的批处理利用 < > << >> 输出流生成中间文件,再经过处理之后,就成为下一个需要用的参数。也可以生成一些配置文件,作为其他工具使用的参数来处理。如果批处理的功能遇到问题,也可以通过模板,利用输入输出流生成一个临时批处理来操作。不要太信任二进制文件,但一定完全信任纯文本。
比如获取文件名,用dir /b > list.txt生成一个list文件,然后用for /f %%i in (list.txt) do echo copy /y %%i %TEMP%\%%i.bak类似这样的循环操作,操作完del list.txt,这就成为一个备份文件的好例子。
dir /b > list.txt
for /f %%i in (list.txt) do echo copy /y %%i %TEMP%\%%i.bak
del list.txt
再举个例子,我写了个工具,是一个命令行打包的工具。但支持的参数类似这样的格式:
#-------------------
#(路径) (类型)
%TEMP%\script script
D:\Work\images bmp
然后打包成一个我需要的文件。我通过使用%cd%获取当前目录,然后获取合适的路径再调用我自己写的打包工具。
echo %TEMP%\script script > pack.txt
echo %cd%\images bmp >> pack.txt
packer pack.txt
del pack.txt
这样一个简单的批处理,就让我的工具做到与环境无关的通用性了。而且参数可以通过生成这个配置文件可编辑。
6、脚本语言。
现在脚本语言越来越多了。awk,perl,python,lua,ruby,javascript,甚至java和C#都可以参与进来。
为什么要用到脚本语言。就是为了作为批处理功能的补充。我在第一条说过,批处理的定位是组装车间,不是加工车间,而加工车间,交给脚本语言。
学一种甚至几种脚本语言是非常有必要的。
虽然上面我用了awk,但awk并不完全推荐,局部简单的还可以,其功能完全可以被perl替代。awk的速度优势,在现在的计算机速度下,已经可以忽略。
而我常用的单行命令基本可以用perl替代,而非单行的脚本可以用python也可以用lua来写。
为什么要用到脚本语言:
a.批处理对于字符串的处理是很弱的。缺乏更好的替换,缺乏类似printf这样的格式化输出,更缺乏整个Template替换。但写一个简单的perl脚本或者python脚本就完全弥补。
b.批处理缺乏数值计算的能力。有的地方日期和数值比对是很重要的。
c.批处理缺乏合理的数据结构,数组,key-value的表格。而针对字符串生成数据结构的split和join的字符串处理。
顺便说一下个人的喜好问题,我是强烈的反感带“VB"两个字母的东东的,比如VBScript我是绝对不用的。
最后,没什么可说的了。
提醒一下,关于字符串以及文本的处理,可以说,你能想到的,20多年前美国玩操作系统的那些老家伙都想到了,你没想到的,那些老家伙也想到了。利用管道很多都可以做到。
引用荀子的一句话:吾尝终日而思矣,不如须臾之所学也。 |
-
2
评分人数
-
|