批处理学习笔记

一:批处理是什么
  批处理是什么呢?说白了批处理就是一种规则,一种外国人制定的规则,我们只要遵守就可以学习了!也可以理解为批处理是编程语言,编程嘛,就是和计算机说 话,你说的好,它就干活,你说的不好,过不了四级就别指望毕业的时候发毕业证,很不幸我现在还没有过四级,这是一项太难的任务了!
  批处理说话的第一条——理解特殊符号
二:批处理中的特殊符号
  学会批处理中的特殊符号对于我们学习编写批处理是非常有用的!这里我做了一下简单的整理—— :、::、&、&&、>、>>、|、||、nul、con、%、(),成对出现的东西是非常容易记忆的,下面 我们结合具体的操作仔细的理解!
1:“:”与“::”
  “::”与rem命令是一样效果,起解释说明的作用,和C++中的/……/一样!
  “:”符号的作用是标记一个标签与goto语句一起使用,其格式为: label,这点与C或C++中的goto语句是截然相反的,在C或者C++中的格式为label:!举例说明:
@echo off
::标签的使用与goto语句
goto test
:test
echo goto语句test
  当然goto语句的跳转是有条件,在后面的批处理结构中你会发现goto语句的魅力,这里只是为了更好的理解上面的两个特殊符号!
2:“&”与“&&”
  “&”与“&&”符号的作用是连接两个命令同时执行,区别在于前者不管第一条命令的执行是否成功,都会执行第二条命令,而后者只有在第一条命令执行成功以后才执行后面的命令!
  例子我们在学完第三组命令“|”与“||”在举!
3:“|”与“||”
  “|”符号的作用是将|前执行的命令结果作为其后DOS命令的参数,比如dir|find "2008",dir命令查看当前目录的文件,然后所有目录的列表作为find "2008"的参数,也就是从该文件目录下查找所有2008年建立的文件!
  “||”符号的作用与“|”是截然不同的,它也是连接两个命令同时执行,不过是第一条命令执行错误的条件下才会执行第二条命令!
   编写如下代码,保存为checkuser.bat:
@echo off
set a=
set/p a=请输入要查找的用户名
net user %a% >nul 2>nul && echo 存在该用户 || echo 用户不存在.
  这是Visual bat程序安装目录中非常经典的一个批处理,它的作用是检查用户输入的帐户是否存在,当用户输入账户后,比如hacker,然后执行net user hacker,如果是存在该帐户也就是说命令执行成功了,那么就显示存在该用户,如果不存在该帐户也就是net user hacker命令没执行成功,就显示用户不存在,结合上面的内容我想您已经理解“||”“&&”“&”三者的微妙之处了!
4:“nul”和“con”
  在checkuser.bat中,我们看到>nul 2>nul的句子,前者是当命令执行成功后不显示回显,比如net user hacker /ad >nul这样用户添加成功后也不会有提示,后者是命令执行错误后不显示回显,两者同时使用的结果就是不论命令执行是否成功,都不显示任何信息!对于 “nul”这个特殊符号我们可以理解为空字符的意思,除了不显示回显,还可以使用它删除文件,copy nul >1.txt或者type nul>1.txt,这种删除方式是比较安全的,我想当初李开复如果使用这种方法删除文件,也许就不会招来因为跳槽而导致的官司!
  对于“con”,我们可以简单的理解为屏幕,在cmd下我们输入:copy *.txt con,可以连续打开多个txt文件以方便我们查看!
5:“>”与“>>”
  “>”它的作用是创建一个文件比如echo hacking >1.txt,而“>>”的作用是将内容追加到一个文件后面,比如前面1.txt的内容为hacking,在CMD下输入echo hacker>>1.txt,那么1.txt的内容为hackinghacker!
6:“%”与“()”
  把这两个符号放一起有点牵强,“()”起分隔符的作用,在后面的批处理中你会理解这点,在批处理我们可以理解为存在两个分隔符一是空格另一个是括号,这时 候的“()”类似于c或者c++中的语句结束符“;”,很多时候我们还使用它包括多条DOS命令,这时候又有点类似于c或者c++中的{},起包含语句块 的作用!
  “%”它的作用是表示变量,而且在批处理文件和在命令行下书写格式不一样,在命令行下使用%variables,在批处理中我们使 用%%variables或者%variables%(不同命令使用不同格式),对于原因,我想它类似于c或者c++中的“转义”,在编程语言中,为了某 些特殊的需要提出了“转义”的概念,顾名思义就是转变符号的原有意思,比如\a是响铃!举个例子来说明%的意思,在C++中我们要在屏幕上输出一个“ \”,则应该写做cout<<"\\";,如果要输出两个“\”则应该写成cout<<" \\\";,这个过程有个很好听的名字“脱逸”,%也遵循了这样方法,在后面我们将结合for命令详细的说明!
   提到“%”号,就不得不说一下参数,所谓参数是在批处理文件(开始说的每个批处理文件是一个外部命令)后所添加的以空格分隔的字符串,它的使用方法 是%1-9,参数是针对批处理文件做为一个外部命令来说的,虽然参数和变量不是一个概念,但是它是按变量来处理的,所以有时候我们也就称为变量了!举例说 明!
@echo off
md %1
md %1\天下1
md %1\天下2
md %1\天下3
保存为test.bat我们在CMD下输入:test.bat 天下,执行后会在批处理目录中建立一个名字为“天下”的文件夹而且在该文件夹下会一次建立三个子文件夹,这当我们输入“test.bat 天下”的时候“天下”就作为参数传递给了%1,即%1=天下!
另 外%variables%的作用是引用环境变量!环境变量可以简单理解为系统已经设置好的系统变量比如%systemroot$是 c:\windows,%compsec%代表的是c:\windows\system32\cmd.exe,对于系统设置好的环境变量我们可以在CMD 下输入set查询,当然我们也可以使用set命令设置环境变量!
  下面我们看批处理中的控制结构!
三:批处理中控制结构
  批处理中有四种控制结构:if结构、goto结构、for循环结构、call结构!,对于call和goto结构应该算是以类,主要是因为它们都具有跳转功能,让很多小批处理转化成大批处理,有点结构化程序设计的味道! 
   call命令的作用是调用其他的批处理文件,比如:call test.bat,而goto语句在文章开始我们就做了解释,所以我们主要说的就是if结构与for循环结构,首先我们先理解条件这个词的意思,把世界看 成一个连锁体系,每一个事情的前一个事情就是该事情的条件,举个简单的例子,我们坐公交车前需要有1元的零钱,这里1元的零钱就是我们坐车的一个条件,当 然在批处理或者程序中就不能那么的表达,在C++中条件其实只有两种:一种靠关系运算符实现,一种靠逻辑运算符实现,批处理中也遵循了这样的规则,当然在 批处理使用最多条件还是靠“=”来实现!
(一)if结构
  在CMD下输入if /?,我们会发现if有三种结构,我们先看这三种结构!
1:IF [NOT] exist filename command
  这应该是最简单的一种IF结构,例如if exsit c:\1.txt  type 1.txt、if not exsit c:\1.txt  echo xxx>c:\1.txt!
2:IF [NOT] ERRORLEVEL number command
  对于number,在DOS时代这个东西有N多比如1、2、3等等而且每个数字都有不同的意义,并且多个number排列时还有规则,在Windows中 其实我们只要注意0和1就可以了!0代表的是程序执行成功,1代表的是程序执行失败!我们可以简单将errorlevel理解为一个变量!所以这个命令还 可以这样书写:IF [NOT] %ERRORLEVEL%==number command
  我们举个简单的例子:
net user hacker 123 /ad
if %errorlevel%==0 echo 添加帐户成功
上面的内容我们还可以这样写:
net user hacker 123 /ad
if not %errorlevel%==1 echo 添加帐户成功
  这两种表达看似等效,其实并不等效,第一个是只有用户添加成功的时候才显示添加帐户,而第二种的意思是不管添加成功还是本机已经存在该帐户,都会显示添加帐户成功,它们之间存在细微的差别!not相当于一个修饰,大家要善于分析条件!
3:IF [NOT] string1==string2 command
  这种if结构也是非常有用的,这里首先需要注意等号是两个,其次注意引号并不是必须的,我们可以不加引号,加引号只是为了防止空字符!
  举例说明,以前很多文章中都涉及到cmd加密器的问题,就是让用户在运行cmd的时候,首先输入密码!网上有更复杂的,其实批处理学到这里我们就可以写出一个比较简单的cmd加密程序!
@echo off
set /p %%a=请输入密码
if %%a==hacker goto test
:test
echo 密码正确,登陆成功
start %comspec%
3:if……else结构
  在运行上面的批处理过程中,你会发现我们输入任何字符都可以运行cmd!编辑如下代码就不会出现上面的问题了!
@echo off
set /p %%a=请输入密码
if %%a==hacker (goto test) else goto error
:test
echo 密码正确,登陆成功
start %comspec%
:error
echo 密码错误 
  这里我们不讨论为什么会出现这样的错误,我们看在批处理中if……else结构的具体使用!在文章开始我们提到批处理是逐行逐句解释执行的,所以我们在用 到if……else语句时,最好直接写到一行,写到一行我们需要注意,将if后面的命令,简称if子句,用括号括起来就好了,我想原因也许还是逐行逐句解 释执行的,这里的()起的作用和空格一样就是分隔作用(上面提到过),一句话if……else语句,在批处理需要放到一行,并且if子句需要用括号括起 来!
5:/i开关
  if结构语句中有一个开关/i,使用该开关,在执行字符串比较的时候不会区分大小写!而且还可以使用如下运算符:
    EQU - 等于
    NEQ - 不等于
    LSS - 小于
    LEQ - 小于或等于
    GTR - 大于
    GEQ - 大于或等于
  书写如下代码:
if /I %time% LEQ 06:00:00.00 goto g1
if /I %time% LEQ 12:00:00.00 goto g2
if /I %time% LEQ 18:00:00.00 goto g3
if /I %time% LEQ 24:00:00.00 goto g4
:g1
net user administrator 123 && goto end
g2:
net user administrator 456 && goto end
g3:
net user administrator 789 && goto end
g4:
net user administrator 023 && goto end
:end
echo OK %time% 密码修改成功,下次登陆请注意
  这段代码的意思是根据当前系统时间自动修改计算机登陆密码!结合上面的解释,应该很容易明白,所以这里不在做说明!
  下面说批处理的精华所在for循环结构!
(二):for循环结构
1:for variable in (Set) do command (command-paremts)
  循环的意思是一次次的重复操作,至于操作什么,如何操作,操作多少次,我们都需要运用命令去自己设定!
  CMD下的for循环基本结构:for variable in (Set) do command (command-paremts)
  对于上面的结构首先我们先明确批处理中的for循环结构有三个关键字——for、in、do,这是使用for循环结构必不可少的!对于变量我们需要注意在 批处理文件中遵循%%即双百分号,在cmd中一般使用%即单百分号,而且在for循环中变量只有52个,(a-z A-Z)可用,对于set的理解就多了,是一个很模糊的概念,可以是一个循环条件,也可以是一个文件、一个目录,command不仅可以是一堆DOS命 令,还可以是一个批处理文件,所以后面才可以添加command-paremts!
  比如for %i in (*.bat *.txt) do del %%i, 这条语句是指,在当前目录下搜索所有BAT和TXT文件,并逐个将搜索到的文件名存入变量%%i中,每搜索到一个,就执行del命令删除%%i变量中指定的文件。
  for循环的/D参数和该用法是一样的,就不在单独说明/D参数的使用方法了!
2:FOR /L %variable IN (start,step,end) DO command [command-parameters]
  参数/L用来将循环指定在一个数字集合内,指定了起始数,每次循环递增/减的数字,以及当数字超出什么范围时循环结束。例如:for /L %c in (3,1,5) do echo %c!
  这条语句是指循环开始时首先将3这个数字存入变量%%c中,并用echo语句显示出来,然后循环每执行一次,这个存入的数字就加1(即在命令格式中的“步进”值),直到数字超出5,循环结束。这段语句的结果是依次显示3、4、5。
3:FOR /R [[drive:]path] %variable IN (set) DO command [command-parameters]
  这个格式操作的对象是一个文件集合,可以是一个目录的名称,也可以是使用通配符的文件名,另外,还可以使用形如“1.txt 2.txt 3.txt”的文件集。/R的参数是让for支持子目录搜索!
  比如在在肉鸡上我们见到了很多txt文件,我们单个下载太复杂了,可以在CMD下输入:for %i in (*.txt) do copy /b all.txt+%i all.txt,将所有txt文件合并为一个all.txt文件!
4:FOR /F ["options"] %variable IN (set) DO command [command-parameters]
  现在我们只想要姓名和QQ两列内容,我们可以在CMD下运行:for /f "eol=; tokens=1,5 delims=, " %i %j in (writer.txt) do echo %i %j >> newwriter.txt!
  在我们运行的命令中,“eol=;”是指忽略以分号开头的行,就是说如果某一行如果类似于“;test1……”,那这行将不被循环处理。 “tokens=1,5”是指提取分离出来的第1个和第5个元素,“delims=,”是指分割方式,空格和“/”则无需指定,直接作为默认分割符。经过 这样分离循环后,一行中的第1个和第5个元素被分别赋值给了变量%%i和%%j,刚才一行资料中的第1个元素是姓名,而第5个元素则是QQ,然后再将这两 个存有所需元素的变量值追加写入到newwriter.txt中,之所以用追加写入,是因为循环要处理很多行,如果不使用“>>”追加在末尾 的话,则会覆盖掉上一行循环中写入的数据。这点往往是我们for循环语句执行得不到正确文件的原因,在使用for循环结构生成文件的时候需要特别注意!
  另外还有一个参数经常用到——skip,它指定了循环从什么时候开始执行,比如for /f %i in (1.txt) do type 1.txt,我们运行后,批处理会不处理1.txt文件中的第一行内容!
5:“%”与“%%”
  前面我提到变量的使用原则,很多人都不明白这个原因,通过for循环结构可以很好的理解,为什么这么说呢?首先,命令行中使用for时不需要双%,这源于 命令解释器对命令行与批处理的处理方式不同!其次在批处理文件中使用双%,因为for功能实现需要执行多条语句,因此它必须也具有对命令行(do关键字后 的命令)分析处理的功能,而CMD实现for时自然会借用自身原有的命令行分析模块,因此for具有二级转义的特性(转义在前面特殊符号%的时候已经说 明),for中do后的语句被分两级解释,第一级在CMD读入并解释for命令行时,第二级在for读入并解释do命令时,它通常会对同一命令行的进行多 次解释。在CMD中使用的变量在经过第一级转义后,被替换成特定的不变的字符串常量,参与for循环的所有执行过程,而替代变量时则要求在执行(do关键 字后的命令)过程中不断的动态变化,正式这个变化,我们的变量必须保持其原有变量的特性,而不是转换成一个字符常量!
  也就是说,在批处理文件中为了维护do关键字后面的命令动态的执行,确切的说是为了让每次do后命令执行完毕后参数依然是个变量,我们必须使用双%,结合在前文中举的C++例子我想大家应该可以理解了!
四:set命令详解
  批处理我们开始的时候就给出了一个定义——它是一种程序,既然是一种程序,它就应该有变量,所谓的变量是以人为参考的,对于人来说变化的量我们都称之为变量!在批处理中我们使用set命令进行自定义变量的设置!
1:SET [variable=[string]]
  这是最简单的一种set命令格式,首先注意在set命令中等号只有一个,这和if结构中的个数是不一样的,其次注意在set命令中变量使用%variable%的格式,这和for语句中的变量使用格式是不一样的!一句话,set命令和if、for命令都又差别!
  我们输入如下代码,保存为test.bat!
@echo off
set var=这里设置变量值
echo %var%
set是命令var是变量名=(只有一个)号右边的"我是值"是变量的值
在批处理中我们要引用这个变就把var变量名用两个%(百分号)扩起来,如例子中的%var%!
2:  SET /P variable=[promptString]
  这个格式是常用的,它就像c++中的iostream头文件,让批处理实现了交互执行!将test.bat的内容修改为如下代码:
@echo off
set /p var=请输入变量的值(0或1):
if %var%==1 (goto test1) else goto test2
:test1
echo 您输入的值是1 &&goto end
:test2
echo 您输入的值是0 &&goto end
:end
echo ok
  这样执行test.bat会提示让我们输入变量的值,从而实现交互操作!
3:SET /A expression
  这里添加了一个/A参数,它的作用的作用就是让SET可以支持数学中的算术与逻辑运算,这个参数非常复杂,复杂于增加了path扩展环境变量,我们先学习简单的用法!
   在test.bat中输入如下代码:
@echo off
set /a var=1+1
echo %var% 
  运行后会得到答案2!set /a 是命令的格式, var变量名后面的1+1是一个数字表达式!我们再举一个逻辑运算的例子, 在CMD下输入:set /a 1"&"1,或者显示结果为1,这里注意在逻辑运算的时候需要将逻辑运算符用双引号引起来!
  /A参数中有一个扩展变量%PATH:str1=str2%,我们将test.bat内容修改为如下内容:
@echo off
set a=hackerxfiles
echo 替换前的值: "%a%"
set var=%a:hacker=hack%
echo 替换后的值: "%var%"
  对比一下运行结果,我们会发现字符串hackerxfiles中的hacker被替换为了hack,从这个例子,我们就可以发现%PATH:str1=str2%这个操作就是把变量%PATH%的里的str1全部用str2替换,这是一种很好的替换字符方法!
  另外扩展环境path还有另外两种格式:%PATH:~-10%和%PATH:~0,-2%,它们用于操作特定元素!%PATH:~-10%格式的例子,将test.bat内容修改为:
@echo off
set a=hackerxfiles
set var=%a:~-3%
echo %var%
  运行结果为les,我们首先给变量a赋值为hackerxfiles,var=%a:~-3%是将变量a的倒数3个元素赋值给变量var!这里的-3可以理解为反向操作特定元素!我们再看另一种格式:%PATH:~0,-2%,将上面代码修改为如下内容:
@echo off
set a=hackerxfiles
set var=%a:~2,-3%
echo %var%
  执行结果:ckerxfi,这是把变量a的值从2位开始,显示变量a总位数-3的位的值得(我们给变量a的的值hackerxfiles有12位,12-3=9),这样他就只显示从第2位开始到第9位的值,并赋予给变量var!
  到这里,我们基本掌握了批处理的核心基础内容,批处理的高级技巧不是在于控制结构而是在于与wmic.exe结合使用! 
五:WMIC——批处理的精华所在
  Wmic.exe是Windows操作系统中的一个命令行工具,使用它可以更方便的管理计算机系统的软硬件设备,批处理+wmic.exe说是一把好兵刃!它有很多开关、命令及参数,这里我们只将其基础,更多的技巧还得靠大家的实际运用!
  在学习WMIC的具体命令格式之前,我们先学习一些基本概念!
1:交互模式(Interactive mode)和非交互模式(Non-Interactive mode)
  如果你在命令提示符下或通过”运行”菜单只输入WMIC,都将进入WMIC的交互模式,每当一个命令执行完毕后,系统还会返回到WMIC提示符 下,如”Root\cli”,交互模式通常在需要执行多个WMIC指令时使用。交互模式有时还会对一些敏感的操作要求确认,比如删除操作,最大现对的避免 操作失误!如果使用该模式,最好在CMD下输入:start wmic,这样可以最大化WMIC运行窗口,使执行结果更清晰!
  非交互模式是指将WMIC指令直接作为WMIC的参数放在WMIC后面,当指令执行完毕后再返回到普通的命令提示符下,而不是进入到WMIC上下文环境中。WMIC的非交互模式主要用于批处理或者其他一些脚本文件中!
2:全局开关
   在CMD下输入:wmic /?会出现很多参数,每个参数都是一个全局开关,顾名思义就是统领全局的参数!这里我们先不讨论每个开关的具体意思,我们的目的是让大家熟悉wmic.exe的常用命令格式!
3:别名
  什么是别名呢?学过编程的都知道标识符,所谓标识符就是在程序中其标识作用的符号,别名和标识符的概念差不多,其作用就是告诉WMIC要做什么,比如proce表示要对进程进行管理,service要对服务进行管理,logicaldisk对磁盘进行管理等等!
4:词汇
  在网上介绍的WMIC中,经常出现动词、副词这些概念,在WMIC中动词一般就assoc、call、CREATE、DELETE、GET、LIST、SET这几个,都是很简单的英文动词,通过英文名字我们就知道这是干什么的!至于副词我们可以理解为动词的参数!
5:命令格式
  在WMIC中的命令格式一般为:wmic+全局开关+别名+wql语句+动词+ 动词参数+动词开关!这个命令格式可以根据需要来写全或者写部份格式!好了,讲了这么多的基础内容,我们举个例子进行说明!
   在wmic里有个别名是logicaldisk(再后面我们还会用到),就是对磁盘进行管理。我们按照上面提到的命令格式从最简单的的学起,在CMD命令 行下(使用非交互模式),wmic logicaldisk list(最简单的结构wmic.exe +别名+动词) 看上去不调理啊,我们加个副词breif修饰一下就整齐多了!
  动词list一般可以用Brief、Full、 Instance、Status、System、Writeable等多个副词修饰,如Brief表示只显示摘要信息,Instance表示只显示对象实 例,Status表示显示对象状态,Writeable表示只显示该对象的可写入的属性信息等。
上边磁盘返回信息当中的DeviceID的值为3 时表示是本地硬盘的分区,如果电脑中有光驱则其值为5,有移动存储设备则其值为2,在网上可以搜索到很多自制U盘杀毒软件,其实就是使用wql语句查询出 移动存储设备的盘符,从而展开病毒查杀的!那么我们该如何选择出移动存储设备呢?我们可以构造wmic logicaldisk where (DriveType=2) list brief!当然要列出本地驱动器可以构造wmic logicaldisk where (DriveType=3) list brief!
  在判断本地计算机移动存储设备的时候,我们往往只需要得到移动存储设备的盘符就可以了,这时候我们需要借助动词get,我们可以构造wmic logicaldisk where (DriveType=2) get deviceid就可以了!
  现在感觉是不是很简单了!再回头看看我们的命令格式,现在我们已经掌握了wmic.exe基本使用方法了!
  再举个例子,当系统出现异常的时候,我们往往习惯性的打开任务管理器,但是WINDOWS Vista以前的版本,任务管理器都有个致命的缺陷——每个进程没有对应的程序运行路径!举个简单的例子,svchost.exe我们都非常熟悉,它位于 c:\windows\system32目录下,如果我们把配置好的***也命名为svchost.exe,把它复制到c:\windows下,通过任务管 理器我们看到svchost.exe进程的时候我们肯定不会怀疑它是个坏家伙!解决这个问题我们就可以使用wmic里的process别名,
  我们在CMD下输入:wmic process where creationclassname="win32_process" get caption,executablepath,就会得到当前系统所有进程与其执行程序的路径! process是别名告诉wmic.exe要对系统进程进行管理,where creationclassname="win32_process"是我们的wql语句,get是我们使用的动 词,caption,executablepath就是动词参数,告诉动词要操作什么!