[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖

[其他] 批处理之我见

本帖最后由 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

评分人数

    • vsbat: 难得有前辈出来技术 + 1
    • cjiabing: 专业,中肯,敬佩~技术 + 10

2011年11月8日,亲,穿越了

前些日子给实习生讲课还提到了肯.汤普森和丹尼斯.里奇,谁知道没过几天大师就 ...
Batcher 发表于 2011-10-19 20:29



    失误,没仔细看。哈。

TOP

20 年前的批处理绝不会比现在挖掘得更充分,强如微软也不可能把还没出现的 cmd 吃透,不说别的,三四年前的 ...
CrLf 发表于 2011-10-19 19:30



    20年前,换句话说,非windows时代。设计和使用Unix和类Unix的那些老家伙们玩的,比最初的dos强了不知道多少。windows就没在CLI定位太多,但Windows的CLI方式都是从Unix系统借过来的。我建议去看看《程序设计实践》这本书。Brain Kernighan和Rob Pike的经验是足够让人借鉴的。

TOP

可以说,遵循Unix哲学,如果能用工具根据配置生成一个批处理去用,就别用手写。这是我坚信的一条。

TOP

我写的打包是给游戏用的,游戏专用的虚拟文件系统。并不是压缩包。。。

TOP

本帖最后由 leeonix 于 2011-10-19 21:47 编辑

概括总结,图片处理,是一个从32位色点阵图,转化为d3d纹理文件,打包进虚拟文件系统的工具。脚本是把文本文件,编译为byte code,然后打包进虚拟文件系统。其他的文件也类似,比如声音文件。其实这个工具也只是调用了游戏用的打包解包库的一组简单的Lua脚本。复制好,最红用zip -9 -r打包为zip文件发送。

TOP

类Basic语言包括VB并没有任何好的帮助。而且这些语言是有害于思考的,编程人员学习语言,其实是学习符号系统,可以说,如果一种语言没有任何值得学习的地方,就不要学。

TOP

我不是平白无故说这个,而我在大学里半年学期就是在学VB,而同时我在自学Delphi。10多年过去了,我会的语言很多,从C/C++ delphi perl python lua falcon asm ActionScript C#,粗略了解过Java php 和javascript。这一系列语言都给我带来帮助,而VB以及我14年前学的Quick Basic,除了有害没有别的,我都已经忘了Basic语言到底该怎么写了。10年前的RAD快速开发方面比delphi差了不止一个档次,而现在和C#更不是一个档次。扩展性方面,只能用COM扩展还得借助VC或者Delphi。而且瓶颈开发的方式,最终只能调用Win32 API,其实还不如用C语言浅显易懂。尽管现在微软弄了VB.net,给我的感觉,还是一个可笑的玩具。

TOP

VB易用归易用,还没有看到我说的“有害”二字?学习一种有害于以后自己发展的东西,是应该完全摒弃的。

  Visual Basic 是一种给儿童和菜鸟程序员的语言,它自从设计开始就是一种简单的语言。一些 C++ 和 Java 中的特性在 VB 中并没有出现。在感受开发的方便和快速的同时,一些类似于编译时进行类型和声明检查的功能在默认情况下是关闭的。这样一些程序员一边感叹 VB 的易用性,一般沮丧地地看着一些类似于“未定义类型”错误的发生。
  一些批评家认为 VB 的简单特性使得其在未来具有伤害性。很多人自学了 VB,但是并没有学到好的编程习惯。当 VB 进入课堂的时候,学生们不会学到很多基础的程序技术和结构,因为很多技术已经包含在那些对用户可见的组件里面了。不用学习标准的编程习惯,因为 VB 具有可视化的特性,所以导致了一些莫名其妙的代码的产生。而且很多错误和警告的检查默认情况下都是关闭的,程序员很难找到隐藏的错误。有经验的程序员在用 VB 编程的时候都会把这些选项打开。
  一些批评家批评微软简单地拷贝了 BASIC的思想到 VB 中。
  Visual Basic 开发的程序只能运行在 Microsoft Windows 中;VB 程序在运行时还需要 VB 运行库。
  Visual Basic 不能很好的综合Windows 的基础 API,很多时候要使用低级运算的“小伎俩”来进行编程。而 C 语言的低级内存运算比 VB 的要简单得多。

TOP

我看那些高人教育初学者的时候说,一般情况下,少用临时文件。虽然没有UNIX那种`xxx`或者${xxx}的命令替换, ...
awk 发表于 2011-10-19 23:45



我当然知道可以直接用dir /b生成临时字符串放到for里面用。但中间呢?批处理最大的问题就是没有数据结构支持。倘若我需要生成一个list.txt的时候,会通过其他方式再处理一次这个list.txt。然后再用for去做。我只是举个利用纯文本的例子,根据一个简单的备份例子解释生成临时文本的方式而已。
grep给你的功能是过滤。多数的管道操作就是由grep处理然后再交给sed。而不是在awk里面写判断。遵循一件工具做好一件事的原则。grep从unix出现到现在,为什么没有呼吁其他工具替换他,这就是威力所在。
我并没有看到批处理有这四个操作符"."(所有字符) "*"(0个或多个) "^"(行首) "$"(行尾),如果你认为有,那就有吧。批处理有吗?你看到了吗?

TOP

本帖最后由 leeonix 于 2011-10-20 08:42 编辑
不同的环境下,每个语言总有自己的擅长之处,最后都是二进制,就看使用的人觉得那个更方便和快速;

编程 ...
plp626 发表于 2011-10-19 23:55


那是你干的太少。选工具才是首选。因为语言涉及到一个大脑思维的过程,干久了会影响你的思维习惯。
我记得10年前有个形容VB,Delphi,和VC++的有个著名的例子。
三个程序员造桥,VB用手头的工具造了一个颤颤巍巍的桥,Delphi用别人的材料造了个坚固耐用的桥,VC则是自己种树自己炼铁最后造了个桥。

可以说学Delphi的拿过问题来首先想到的是找控件,VC的是找代码然后自己做。
而学VB的拿过问题来,遇到VB干不了的事情,就基本是束手无策了。
这就是影响人的思考方式的可怕之处。

TOP

无论是哪种编程语言,归根到底都只是人类利用的一种工具。至于好与不好,那是因人而异的,不是说 ...
broly 发表于 2011-10-20 01:48


因人而异,是没错。但人在使用工具的时候,也会养成使用工具的习惯。好习惯和坏习惯都会伴随终身。如果已知一个工具可以养成坏习惯,为什么要去养坏习惯?
多年前,谭浩强教授的那本书让很多人养成了写C语言的各种坏习惯,然后现在不知道有多少人在骂谭老头。
而VB从根本就带来了各种各样的坏习惯。而且语言本身带来的概念太多,而且面向对象也是不完全的。多花时间去学一下VC和MFC比学VB要好的多的多。

TOP

我看那些高人教育初学者的时候说,一般情况下,少用临时文件。虽然没有UNIX那种`xxx`或者${xxx}的命令替换, ...
awk 发表于 2011-10-19 23:45


对了,是没有替换命令。但是用Python完全可以做到,只需要一个lambda就可以替换${xxx},然后交给批处理用。

TOP

本帖最后由 leeonix 于 2011-10-20 09:00 编辑

最后我说一下我为什么扔掉VB,然后可以终止这个VB的话题了。
大概是1999年下半年,我还在上大学的时候,在一个个人办软件公司里打零工,老板姓武,我就叫他武老师。当时VB很流行,老师也在用。当时我说,学校里学的都是玩具的东西,我想跟老师深入学学用VB,老师笑呵呵的打开了Delphi4,然后再打开VB6,说,这个东西其实就是拖拖控件然后写一些东西。你看看VB,才那么几个控件,你再看看Delphi,好几排控件比VB多得多,所以干脆你直接学Delphi得了。下午我就去买了本delphi5从入门到精通。就我知道武老师当时的项目已经从VB转向Delphi了。

其实我当时开始学Delphi实际上是被控件多给左右思想了。而今,我一直很庆幸当时没有选择用VB。VB出问题了,你不知道哪里出问题,找错误都费解。而Delphi,市面上的版本都是带源代码的。如果你不懂,可以看看它是怎么工作的,然后你就知道错误在哪了。

TOP

>>倘若我需要生成一个list.txt的时候,会通过其他方式再处理一次这个list.txt。然后再用for去做。
>>不是很懂,不知道为什么要拐这么多弯。
我不知道为什么纠结与这个简单的例子,我知识举个生成纯文本使用的例子而已。没别的,有两点优势,
第一,组织自己的结构。
第二,保存一个文件,如果出错就可以看到这个list.txt到底错在哪里,类似一个日志。所以我宁愿生成个文件,也不会写类似for /f in ('dir /b | grep "*\.*"') do这样的。而且后面的删除给别人前都是被注释保留的。

>>grep给你的功能是过滤。多数的管道操作就是由grep处理然后再交给sed。而不是在awk里面写判断。
>>不错,grep是过滤,但是sed/awk本身可以过滤啊,不用你自己写判断呀。干嘛又是grep又是管道呢?说到呼吁什么东西代替它,别逗了,不在一个层面。

我当然知道类似awk在后面是可以用~=加条件过滤是不是显示前面的条件,sed也是可以的。但经常使用grep的人都习惯使用grep,因为日常的工作,操作grep远远多过sed和awk。结合grep和管道做事,这也是我说的习惯的问题。我用vim写代码,使用各类shell,一天要输入grep至少60次以上,像vim自己就有查找vimgrep,为什么vim自己还加了调用外部grep的接口?无它就是习惯而已。

>>然后现在不知道有多少人在骂谭老头
>>确实有很多人在骂。我感脚吧,这面不少人是看了几本外文C教材就觉得自己有两把刷子的。而那些低调的高手们给出的评价往往显得谦逊:人家谭老师毕竟让那么多中国人迈进了C门槛。
我和你的观点是一样的,而且我不是骂老谭的那群人的一员。在80年代,那么封闭的年代,连县城的书店都不一定买得到道德经的时代,没有互联网的时代,老谭的书让人知道了BASIC和C语言。是一代人的领路人。但后面随着新的书籍的进入,老谭还用他的书和教学,就是在误人子弟,那就真的找挨骂了。像类似高校的,比如邱钟潘的“教授”,还有臭名昭著的清华大学出版社。你可以搜索一下有多少人骂。我只是老谭的反例,阐述一个坏习惯的问题。坏习惯养成了想改都很难改。

>>对了,是没有替换命令。但是用Python完全可以做到
>>有哪种语言或者脚本做不到吗?
当然有,他叫做“批处理”或者叫Batch,批处理本质上就是一种“脚本语言”。还有某些小语言,还有某些叫做语言的。比如XML,HTML。XML也是一种叫做“语言”的东西。

TOP

返回列表