批处理脚本学习笔记——程序猿版


批处理脚本学习笔记

原创作品。同意转载,转载时请务必以超链接形式标明文章原始出处、作者信息和本声明。否则将追究法律责任。http://blog.csdn.net/taotaoyouarebaby/article/details/23958897

说明:本文档在LGPL开源协议下公布。本文档将批处理当作一门编程语言来看待,按编程语言的元素来组织内容。

这份文档是目的不是教你各个命令的语法。而主要集中在批处理是如何实现普通编程语言的一些功能,当中的语法说明使用的是BNF规则。

文档有一定难度。不适合于连批处理是什么都不知道的情况。假设你有点编程语言基础那就更好了。

完完整整的把批处理看下来,得到一个结论就是,批处理功能很有限。很难当作一门完整的编程语言来看待。拷贝到网页上之后格式有点乱,所以提供PDF下载

1  cmd解释器基本工作原理

全部命令不区分大写和小写。除for的循环变量。

cmd解释器按逻辑行读取和运行。

行在这是的含义:1.以回车为结束标志的一自然行。

2.通过()和&&,||,&组合在一起的多个自然行。

读取一行之后,会运行以下步骤

1)  变量替换:将參数变量(%0, %1,...,%9)和以%号引起来变量(eg: %path%)替换为实际值。

2)  去除被转义的特殊字符的语义。转义字符:""(对之间的全部元字符转义), ^(对单个字符转义)

3)  运行语法检查,生成指令序列。

4)  运行重定向

1.1         延迟绑定技术

语法:

setlocal EnableDelayedExpansion | DisableDelayedExpansion

set var=!var!;...

...

endlocal

功能:

1)  使用变量在逻辑行运行过程中的实际值(动态变化),而不是读取逻辑行时的值(不变,仅仅是简单替换)。主要用于for语句。假设不启动的话,for语句中使用set命令时,多数情况下无法得到想要的结果。

2)  须要延迟绑定的变量,通过!var!的形式来获取值。支持相同的字符串操作。

1.2         命令扩展

语法:

setlocal EnableExtensions | DiableExtensions

...

endlocal

功能:打开一些命令的扩展功能。

2  批处理基本的语法

凝视:

rem anything

:: anything. 解释器无法识别::所以会抛弃这一行,达到凝视的效果。

由此能够得到其他的凝视方式。

2.1         变量

2.1.1   简单变量

定义:

set variable-name=value{value}

value := %var% | %1 | string | numbers

说明:

1) 变量名与变量值之间不能有空格

2) 变量值不能有特殊字符。假设有则须要转义

3) 变量能够反复定义。

重定义时会覆盖之前定义的值。

4) 从用户输入或文件取得变量值

set /p var=提示语句

set /p var= < file.txt

删除:

set variable-name=

显示:会显示全部以variable-name为前缀的变量的值

set variable-name

引用:

%变量名%

使用演示样例:

@echo off

set var=value

echo %var%

pause

输出:value

2.2         输入输出

2.2.1   输出

控制输出

描写叙述

演示样例

echo

输出一行信息

echo %var%    输出变量值

echo %1        输出命令行參数值

echo some-message. 输出随意信息

echo >>file.txt str 等同于:echo str >>file.txt

type

打印文本信息到标准输出

type a.txt    显示a.txt中的内容

more

逐屏显示

type a.txt | more +3

CLS 

清屏

路过前3行,逐屏显示a.txt内容

COLOR 

设置cmd文字与背景颜色

color 07  背景(0:黑色)文字(7:白色)

TITLE 

设置cmd标题,常当作进度条

@title welcome to GOD 进度条程序

@

隐藏命令

@echo 不显示命令

time /t

显示当前时间

 

2.2.2   标准输出输出句柄

句柄

等价的数字

描写叙述

STDIN

0

标准输入。即键盘输入

STDOUT

1

标准输出

STDERR

2

标准错误输出

UNDEFINED

3-9

应用程序定义

2.2.3   输入输出重定向与管道命令

命令

描写叙述

将标准输出重定向到文件,即将输出写入文件。以覆盖方式写入

>> 

将标准输出重定向到文件,即将输出写入文件。以在尾部追加的方式写入

将标准输入重定向到文件,即从文件里读取输入数据

|

a | b。将a命令的输出作为b命令的输入。名叫管道

<&

管道合并命令。

a<&b 等价于 b>&a。

将要输出到b的内容。输出到a。将b管的出口合并到a管的入口。

经常使用形式:type a.txt > b.txt 2 >& 1。将type的错误信息输出到标准输出。并将标准输出重定向到文件。

>&

常见:

1)  command > nul  等价于command 1>nul : 不显示command命令的输出信息。

eg: copy a.txt b.txt >nul.这样一来就不会显示复制完毕的提示信息了。

2)  command 2>nul : 不显示command命令的标准错误信息。

2.3         字符串

2.3.1   经常使用字符串操作

操作

描写叙述

定义/创建

set str=a;b;c;d

连接

set str=%str%otherthings

替换

set str=%str:a=c%  把str中的全部a替换为c

set str=%str:*;=%  把str中从開始到’;’为止(包括’;’)的全部内容替换为空(即删除)

剪切

%str:~start[,end]%

1)   字符串下标从0開始。

得到的字符串,假设start==0, 为(str[start],str[end-1]);start!=0, 为(str[start], str[end])。

2)   start,end的取值区间:(-len, -1] & [0, len-1),负数表示从后往前数的位置。

str=a;b;c;d

%str:~1%    

;b;c;d

%str:~0,2% EQU %str:~1,2%

a;

%str:~1,-1%

;b;c;

清空

set str=

2.3.2   处理字符串中的保留字符

windowsNT的保留字符:& | ( ) < > ^。

当字符串有以上字符仅仅须要使用字符’^’对其进行转义。

普通情况:

set var=dir ^> file.txt   & rem 转义单个保留字符

set var=”dir > file.txt”  & rem 会转义双引號中的全部保留字符。但var中会含有双引號

嵌套时:

@IF NOT "%~1"=="" FOR /F "tokens=2*" %%A IN (

'REG Query HKLM\SOFTWARE\PHP /v InstallDir'

) DO (

@FOR /F %%C IN (

'%%~sB.\PHP.EXE -r "print^(md5^(\"%~1\"^)^)^;"'

) DO @SET MD5=%%C

)

说明:each level of nesting would require an extra "level" ofescaping

2.3.3   演示样例

显示一个变量中全部以分号分隔的字符串。

@echo off

set myvar=a b;c;d

set strippedvar=%myvar%

:repeat

for /f "delims=;" %%a in ("%strippedvar%") do echo %%a

set prestrippedvar=%strippedvar%

set strippedvar=%strippedvar:*;=%

if not "%prestrippedvar:;=%"=="%prestrippedvar%" goto :repeat

2.4         算术运算SET /A

支持的数

Octal:

SET /A Result = 020

Decimal:

SET /A Result = 16

Hexadecimal:

SET /A Result = 0x10

Or any combination:

SET /A Result = 010 + 0x20 - 24

算术运算汇总:对全部操作符支持复合赋值(eg: +=, -=)

Add:

SET /A Result = 12 + 4

Subtract:

SET /A Result = 23 - 7

Multiply:

SET /A Result = 8 * 2

Integer divide:

SET /A Result = 33 / 2

Modulo divide: (12)

SET /A "Result = 66 %% 25"

Shift right: (2)

SET /A "Result = 128 >> 3"

Shift left:

SET /A "Result = 1 << 4"

Bitwise AND:

SET /A "Result = 48 & 23"

Bitwise OR:

SET /A "Result = 16 | 16"

Bitwise XOR:

SET /A "Result = 31 ^ 15"

Group:

SET /A "Result = ( 24 << 1 ) & 23"

说明:

1.取模运算。在批处理中使用%%,在命令行中使用%。

2.当表达式包括特殊字符(%&<>|ˆ( or ))时,须要使用双引號引起来。

3.不支持实数(小数)运算

2.5         DOSKEY与命令别名

语法:

doskey macroname=[comand{$Tcommand}] 设置命令别名,等号右边不能以空格开头

doskey /MACROFILE=filename  从文件里导入命令别名设置

doskey /MACROS:ALL > filename  将全部命令别名设置导出到文件

Doskey宏定义的一些特殊代码:

特殊代码

含义

演示样例

$T

命令分隔符。同意一个宏中存在多个命令。

doskey ls=dir$Techo end

$1-$9

接收相应的批处理參数。与批处理程序中的 %1-%9 等同。

$*

接收别名后面的全部參数

doskey ls=dir $*

演示样例:

rem 在cmd启动时设置命令别名

cmd /k doskey /macrofile=macros.linux

doskey  myname=for /f "delims=\ tokens=2" %i in ('whoami') do @echo %i

doskey destroy=del /s /q /f $*

2.6         环境变量

说明:以下两种方式,在当前cmd实例中对环境变量作的改变。在该实例中(及其创建的子实例中,startcmd.exe)是无法获得的。仅仅有在下一次cmd启动时生效。重新启动explorer,批处理中才干生效。

2.6.1   使用wmic操作环境变量

wmic是一个windows系统管理工具。功能很强大。系统支持>=xp, >=server2003。

操作

实现: wmic environment+上以下的

create name="VarName", username="<system>", VariableValue="VarValue"

where "name='Name' and username='<system>'" delete

where "name='Name' and username='<system>'" get Name, VariableValue

where "name='Name' and username='<system>'" set VariableValue="Value"

说明:

1)  可永久性的设置系统环境变量。不会由于退出cmd而失效。设置后在下一次cmd启动时生效;重新启动explorer。批处理中才干生效。

2)  set功能,假设VariableValue跟的是空值。则会删除该变量。

3)  使用username="<system>"。是用于设置系统环境变量的。

假设去掉则是设置当前用户的环境变量。

4)  不能反复create。不能set/delete/get未创建变量。

wmic的使用參见:http://www.cnblogs.com/top5/archive/2013/06/19/3143832.html

用于环境变量设置时,为方便使用须要进行一下改造:參见永久设置系统环境变量——by WMIC

2.6.2   使用setx操作环境变量

setx说明:系统支持>=xpserver package 2。环境变量设置,永久有效。不须要重新启动系统。

用法相似一般的set命令。

setx [/M] var-name=[var-value]

说明

1)  /M用于设置系统环境变量。

2)  仅仅能清空。没法删除已经存在环境变量。

3  程序流

3.1         条件运行

3.1.1   组合命令&,&&, ||, ()

命令符号

功能描写叙述

&

a & b, 先运行a,然后运行b。

&&

a && b, 先运行a,假设a运行成功(返回值为0)才会运行b.

||

a || b, 先运行a。假设a运行失败(返回值非0)才会运行b.

()

用于将多行组合成逻辑上的一行命令。eg:

a

) && (

b

)

a,b命令尽管自在不同的行。但解释器会将其当作一行处理。变量替换时会同一时候替换a,b中存在的变量。

3.1.2   IF基本命令

基本的语法:IF [NOT] condition command1[ELSEcommand2] : 假设(不)满足条件则运行command1,否则运行command2。中括号括起来的表示可选项。

IF命令

功能

1.IF [NOT] ERRORLEVEL number command ELSE command。

2.IF [NOT] %errorlevel% op number command ELSE command

检查上一个命令的返回值

1.>= n. 2. op n

IF [/I] [NOT] string1 op string2 command ELSE command

比較字符串/数字。/I不差别大写和小写

IF [NOT] EXIST filename command ELSE command

推断文件(夹)是否存在

IF [NOT] DEFINED variable command ELSE command

推断变量是否定义/不为空

说明:

1. ELSE逻辑上必须与IF在同一行上.

2. op能够上:EQU(==)。 NEQ(!=)。 LSS(<)。 LEQ(<=), GTR(>), GEQ(>=)

3.1.3   IF条件的布尔逻辑实现

布尔逻辑关系:a & b == !(!a | !b), a ^ b = (!a & b) | (a & !b)

IF...ELSE实现

暂时变量实现

布尔算术实现

AND: %1 > 1 AND %2 <10 do command1

IF %1 GTR 1 (

     IF %2 LSS 10 (

        command1

)

)

也可写为一行:

IF %1 GTR 1 IF %2 LSS 10 command1

SET flag=1

IF NOT %1 GTR 1 SET flag =0

IF NOT %2 LSS 10 SET flag =0

IF %flag% EQU 1 command1

IF %1 GTR 1 SET cond1=1 ELSE set cond1=0

IF %2 LSS 10 SET cond2=1 ELSE set cond2=0

SET /A r = "cond1 & cond2"

IF r EQU 1 command1

OR:%1 > 1 OR %1 < 10 do command1

IF %1 GTR 1 (

   command1

) ELSE (

  IF %1 LSS 10 (

command1

)

)

SET flag=0

IF %1 GTR 1 SET flag =1

IF %1 LSS 10 SET flag =1

IF %flag% EQU 1 command1

IF %1 GTR 1 SET cond1=1 ELSE set cond1=0

IF %1 LSS 10 SET cond2=1 ELSE set cond2=0

SET /A r = "cond1 | cond2"

IF r EQU 1 command1

XOR: %1 > 1 XOR %2 > 1 do command1

仅仅用IF...ELSE...逻辑很难实现.

SET flag = 0

IF NOT %1 GTR 1 IF %2 GTR 1 SET flag = 1

IF %1 GTR 1 IF NOT EQU 1 SET  flag = 1

IF %flag% EQU 1 echo TRUE

IF %1 GTR 1 SET cond1=1 ELSE set cond1=0

IF %2 GTR 1 SET cond2=1 ELSE set cond2=0

SET /A r = "cond1 ^ cond2"

IF r EQU 1 command1

3.1.4   循环实现goto,label,if

label:以冒号開始.

:start

:next

:eof

goto语法:

GOTO :label

说明:程序流会从当前位置跳转到label所在位置。

演示样例:卸载程序的菜单

rem 删除部分文件的菜单

:SELECT

    echo 选择须要删除的文件

    echo [1].PGSQL,PostgreSQL数据库程序

    echo [2].PGSQLData,数据库数据

    echo [3].JRE,java运行时环境

    echo [4].TOMCAT, 服务器程序

    echo [5].WEBAPP,站点主程序

    echo [6].退出

    :SELECT_AGAIN

        set /P option="输入要删除的项目[1|2|3|4|5|6]:"

        if "%option%" == "1" goto PGSQL

        if "%option%" == "2" goto PGSQLDATA

        if "%option%" == "3" goto JRE

        if "%option%" == "4" goto TOMCAT

        if "%option%" == "5" goto WEBAPP

        if "%option%" == "6" goto end

    goto SELECT_AGAIN

3.2         for循环

在命令行下for变量使用%,在批处理中for变量使用%%。

3.2.1   for变量及命令行參数扩展功能

语法:

%~[options]var-name

     options := option{option}

         option :=  | f | d | p | n | x | s | a | t | z | $PATH:

     var-name := [a-zA-Z0-9]

 

选项说明:for变量名为单个字母区分大写和小写。命令行參数%0~%9也能够使用这项功能。

各选项能够组合使用。

功能组合

说明

演示样例

%~1

删除不论什么引號(")

%~1 : "C:" -> C:

%~f0

完整路径名:驱动器号+路径+文件名称+扩展名

相当于以下四个的组合。

%~f0: D:\BatchTestDir\forexpvar.bat

%~d0

驱动器号

%~d0: D:

%~p0

路径

%~p0: \BatchTestDir\

%~n0

文件名称

%~n0: forexpvar

%~x0

一个文件扩展名

%~x0: .bat

%~s0

路径,仅仅含有短名

%~s0: D:\BATCHT~1\FOREXP~1.BAT

%~a0

文件属性

%~a0: --a------

%~t0

文件的日期/时间

%~t0: 2014/04/14 11:19

%~z0

文件的大小

%~z0: 306

%~$PATH:1

以I变量为关键字查找path变量,找到则返回第一个匹配,否则返回空。

%~$PATH:1 C:\

%~dp0

驱动器号+路径

%~dp0: D:\BatchTestDir\

演示样例代码:測试全部的变量增强功能

rem 本測试文件完整路径名:D:\BatchTestDir\forexpvar.bat

@echo off

call :show "C:"

goto :end

:show

echo %%~1 : %1 -^> %~1

echo %%~f0: %~f0

echo %%~d0: %~d0

echo %%~p0: %~p0

echo %%~n0: %~n0

echo %%~x0: %~x0

echo %%~s0: %~s0

echo %%~a0: %~a0

echo %%~t0: %~t0

echo %%~z0: %~z0

echo %%~$PATH:1 %~$PATH:1

echo 组合

echo %%~dp0 %~dp0

echo %%~ftza0 %~ftza0

:end

pause

3.2.2   FOR /F 分析文本

语法:

FOR /F ["options"] %variable IN (

   filenames     /*用for解析文件内容。文件名称不能含有通配符。eg: in (dir.txt, dir2.txt)*/

   |"string"     /*用for解析字符串。字符串中不能含有双引號,否则cmd会解析出错。

*/

   |’command’    /*用for解析命令产生的数据*/

) DO command [cmd-params]

说明:

1)  按行解析文本数据。每行解析得到的数据会依次分配给for变量。

2)  options:

eol=c           - end of line. char.指一个行凝视字符的结尾(就一个)

skip=n          - skip lines count. 指在文件開始时忽略的行数。

delims=xxx      - 指分隔符集。默觉得:空格和跳格键。

tokens=x,y,m-n,*  - 指每行的哪些符号被传递到每一个迭代的for变量。

m-n表示范围,*:表示额外的变量将在最后一个符号解析之后分配并接受行的其余文本。

usebackq        - 同意在 filenames中使用双引號扩起文件名称称。

演示样例:

1.分行打印path变量中的每一个路径

@echo off

set str=%path%

:next

    for /f "delims=;" %%i in ("%str%") do @echo %%i

    set prestr=%str%

    set str=%str:*;=%   & rem 删除已经显示的路径

    if not "%prestr%"=="%prestr:;=%" goto :next

:end

pause

3.2.3   FOR /L,标准for循环

FOR /L %variable IN (start,step,end) DO command[command-parameters]

说明:相似于C语言中的for循环:for(i= start, i <= end; i+=step)...。start,end,step都能够使用变量。

set /p size=输入循环次数:

for /l %i in (1, 1, %size%) do @echo %i

无限循环:

FOR /L %A IN (0,0,0) DO command [command-parameters]

3.2.4   FOR /R 递归文件夹匹配文件

语法:

FOR /R [[drive:]path]|. %variable IN (set) DO command [cmd-params]

set := keyword{,keyword}

keyword := 普通字符串 | 通配符(*, ?)

说明:

1)  递归指定的根文件夹(能够用’.’表示当前文件夹),按set匹配文件名称。将匹配到的文件的完整路径传递给for变量。

2)  set演示样例: *.avi(全部avi格式的文件), *learn*.txt(文件名称包括learn的文本文件)。

演示样例:生成播放列表

@echo off

rem create play list.

echo 開始以当前文件夹为根文件夹。递归地生成播放列表。

setlocal EnableDelayedExpansion & rem for中使用set进行算术运算,须要启用变量延迟绑定

set file=playlist.kpl

set n=0

echo [playlist]>%file%

for /R . %%i in (*.mp4, *.avi, *.rmvb, *.rm, *.mp3,*.ape) do (

    set /A n+=1

    echo File!n!=%%i >> %file%     & rem 文件完整路径

    echo Title!n!=%%~ni >> %file% & rem 文件名称

    echo Length!n!=0 >> %file%

    echo Played!n!=0 >> %file% 

)

echo NumberOfEntries=%n% >> %file%

echo Version=2 >> %file%

echo CurrentIndex=47 >> %file%

endlocal

3.2.5   其他FOR功能

FOR %variable IN (set) DO command[command-parameters]

遍历文件

set为一个或一组文件。

FOR /D %variable IN (set) DO command[command-parameters]

匹配当前文件夹中的文件夹,不递归。

set中能够使用通配符。

3.2.6   for中使用set与延迟绑定

for中set命令失效的问题:

SET VAR=str

FOR /F "tokens=1-3 delims=;" %%i IN ("a;b;c") DO (

    SET VAR=%VAR%;%%i

    SET VAR=%VAR%;%%j

    SET VAR=%VAR%;%%k

)

echo %VAR%

结果:

;c

期待值:str;a;b;c

原因:VAR变量在for语句之前已经定义,所以cmd在解释for语句时。会使用VAR变量的值替换for语句中的%VAR%,然后再运行for命令。

实际运行的set语句是:

set VAR=str;%%i

set VAR=str;%%j

set VAR=str;%%k

解决方式

方案一:暂时

仅仅要在for语句之前变量VAR未定义,就会使用VAR的动态值。

方案二:变量延迟绑定技术

运行for语句前不会进行变量替换,直接使用变量在for语句运行过程中的值。

setlocal EnableDelayedExpansion + !var!

setlocal EnableDelayedExpansion

SET VAR=str

FOR /F "tokens=1-3 delims=;" %%i IN ("a;b;c") DO (

    SET VAR=!VAR!;%%i

    SET VAR=!VAR!;%%j

    SET VAR=!VAR!;%%k

)

echo %VAR%

endlocal

结果:

str;a;b;c

3.3         函数

3.3.1   作用域

如何在批处理中建立一个作用域,使用当中定义的变量在外部不可见。方法:

setlocal

...定义变量

endlocal

如何从外部取得setlocal...endlocal之间的值呢?

setlocal

...

endlocal & ( set retVal=%innerVal%)

外部就能够通过retVal訪问innerVal的值。

3.3.2   定义

rem func.bat

:func

SETLOCAL EnableDelayedExpansion

set result1=%~1   & rem 获取函数參数

set result2=%~2

ENDLOCAL & (

  rem 设置返回值

  SET RESULT1=%RESULT1%

  SET RESULT2=%RESULT2%

  exit /B 0    &  rem 退出当前批处理脚本,返回函数运行状态

)

 

退出函数:

exit /B 0

exit /B用于退出当前批处理脚本;从call调用中退出。

3.3.3   调用call

call能够跟文件或标号(Label)。

call 返回后会继续运行call语句之后的代码。

单独的文件 :call func.bat param1 param2

标号Label : call :func param1, param2

3.3.4   函数返回代码%errorlevel%

保存近期一个命令/函数的退出代码(exit...)。能够通过该变量获得上一个命令的运行状态。

使用if语句推断。

4  扩展批处理功能

4.1         模拟数组

未直接提供。可是能够通过简单的set进行模拟。

4.1.1   设计

模拟数组:通过这种方式能够模拟出相似PHP中的关联数组。

定义:set ArrayName[%index%]=value, set ArrayName.length=%length%

取值:取单个值:%ArrayName[1]%, 遍历:!ArrayName[%index%]!

改动:set ArrayName[%index%]=newVal

加入:set ArrayName[%index%]=value, set /A ArrayName.length+=1

删除:set ArrayName[%index%]=   set /A ArrayName.length-=1

当中index ::= 数字 | 字符串

4.1.2   实现

创建数组:

rem CreateArray.bat

rem CALL CreateArray name 10 0

:CreateArray

    set idx=0

    set name=%~1

    set len=%~2

    set initVal=%~3

    for /L %%i IN (1, 1, %len%) do (

        set %name%[%%i]=%initVal%

    )

    set %name%.length=%len%

exit /B 0    

遍历数组:

@echo off

call :CreateArray names 10 1

setlocal EnableDelayedExpansion

    set idx=1

    :loopstart

if %idx% GTR %names.length% (

  goto :loopend

)

    echo !names[%idx%]!

    set /a idx+=1 & goto :loopstart

:loopend

endlocal

说明:使用for /L遍历会失败。原因不知。代码例如以下:

for /L %%i IN (1, 1, %names.length%) do (

    echo !names[%%i]!

)

4.2         模拟对象

4.2.1   对象模型设计

首先定义类,然后依据类创建对象。

构造函数->生成并返回对象名。调用静态数据初始化函数。定义非静态数据成员。

类结构

实现方式

调用

构造函数

ClassConstructor [construct-params]

功能:生成唯一的对象名并返回,生成对象非静态数据成员。

call :Constructor-Label

非静态数据成员

ObjectName.FieldName

!%ObjectName%.FieldName!

静态数据成员

ClassName.FieldName

%ClassName.FieldName%

非静态成员函数

ClassName.MethodName

call :CName.MName %objname%

静态成员函数

ClassName.MethodName

call : ClassName.MethodName

4.2.2   设计问题

n  如何生成唯一的对象名

批处理是单线程的,所以不会出现多个线程竞争的情况。cmd中能够用数字定义变量,所以对象名能够採用timestamp+random的方式,eg:201404171310269930082。并使用if defined检查是否定义。

n  如何初始化静态数据成员?

单独定义一个静态数据初始化函数。每一个构造函数检查静态数据成员是否初始化,假设没有则调用它。

n  类函数成员如何放置

有三种方式:

1)  在使用的位置,该类定义复制过去。使用较少时。

2)  将类成员函数放到不同的.bat文件里。可行。文件会过多。

3)  将一个类的定义都放到一个.bat文件里。通过批处理參数来差别调用的是哪个成员函数。可行,效率低点。

4.2.3   实现

以下的代码,是将类定义放在使用的地方。

4.2.3.1     对象名生成器timestamp+random

rem Utility: name allocator of class.

rem return: number string of timestamp+random. eg: 201404171310269930082

:NameAlloc

setlocal

   :loopstart

   rem 2014/04/17 周四.注意delims后面有一个空格。用于断开“周四”

   for /F "tokens=1,2,3 delims=/" %%i IN ("%date%") do set timestamp=%%i%%j%%k

   rem 14:26:24.55

for /F "tokens=1,2,3,4 delims=:." %%i IN ("%time%") do (

 set timestamp=%timestamp%%%i%%j%%k%%l%random%

   )

   if defined %timestamp% goto loopstart & 变量已定义。又一次生成。

endlocal & (

    set NameAlloc.result=%timestamp%

    exit /B 0

)

4.2.3.2     类定义

rem class: Man

rem ==============constructors of Man==============

rem Man's constructor.

rem RETURN: by Man.ObjBuilder.result

rem         the name of Man's new instance.

:Man.ObjBuilder

    if not defined Man.load call :Man.Static & rem initialize static member.

    rem update static member.

    set /A Man.count+=1

    rem deifne nonstatic member of class.

    call :NameAlloc

    set %NameAlloc.result%.age=10

    set %NameAlloc.result%.name=zt

    set %NameAlloc.result%.work=writer

    rem return the name of new object.

    set Man.obj=%NameAlloc.result%

    exit /B 0

rem function: define static member of Man.

:Man.Static

    rem 类载入标志

    set Man.load=1

    set Man.count=0

    exit /B 0

rem ===============Member function of Man==========

rem non-static, %1 objname

:Man.isWriter

setlocal EnableDelayedExpansion

    set obj=%~1

    if !%obj%.work!==writer endlocal & exit /B %TRUE%

endlocal & exit /B %FALSE%

rem static function

:Man.showCount

    echo showCount:%Man.count%

    exit /B %TRUE%

4.2.3.3     类的使用

@echo off

set TRUE=0

set FALSE=1

setlocal EnableDelayedExpansion

    call :Man.ObjBuilder & rem call constructor

    call :Man.ObjBuilder

    echo %Man.obj% & rem object name.

    echo Count:%Man.count% & rem refer static member

    call :Man.showCount & rem call static member function.

    rem call non-static member function.

    (call :Man.isWriter %Man.obj%) && (echo is writer) || (echo not writer)

    rem show Man's non-static member.  

    echo Age:!%Man.obj%.age!, Name:!%Man.obj%.name!,work:!%Man.obj%.work!

    pause

endlocal

goto :eof

4.3         嵌入PHP代码

环境准备:

1)  下载安装PHP

2)  配置path环境变量

嵌入PHP代码演示样例:获取MD5

@IF NOT "%~1"=="" PHP.EXE -r "print(md5('%~1'));"

4.4         嵌入PERL代码

获取MD5

@IF NOT "%~1"=="" perl -MDigest::MD5=md5_hex -le "print md5_hex '%~1'"

5  批处理任务实战

5.1         站点部署

5.1.1   需求说明

需求:

1)  建立快捷方式以启动tomcat。

2)  建立卸载程序。

3)  支持操作系统:windows, >=xp,>= server2003, x86, x64。

4)  安装路径可配置。

须要安装的文件

说明

JRE.7z

java运行时环境,手动安装包。

须要配置好JAVA_HOME,JRE_HOME,CLASSPATH等环境变量.

TOMCAT.zip

须要在conf/server.xml中配置好站点路径<Context />。

PGSQL.zip

数据库程序。手动安装包。解压会须要创建用户、数据库,并导入初始化数据。配置path。

WEBAPP.7z

解压就可以

AllInOne.sql

初始化数据:表、初始化数据。

5.1.2   须要的工具与技术

需求

技术方案

解压文件

7z.exe, 7z.dll,32位和64位版。

创建快捷方式的工具

1.  直接使用cmd创建。

过于麻烦。

2.  使用VB脚本创建。更好。

3.  桌面位置:%USERPROFILE%\Desktop

环境变量设置

wmic,setx。

优先选用wmic,由于xp中仅仅有sp2中才有。

须要使用.

识别操作系统

环境变量:%PROCESSOR_ARCHITECTURE%

可能的值: x86, x64, amd64, ia64, x86_amd64, x86_ia64

清除设置的path变量

解析path变量的工具。path变量删减工具

 

5.1.2.1     通过.inf文件创建快捷方式

建立例如以下的.inf文件就可以:

[AddLink]

setup.ini, progman.groups,, "group0=%ShortName%"

setup.ini, group0,, ""%ShortName%""

setup.ini, group0,, """%icon1name%"",""%49002%\jscript5.chm"",,0,"

具体參考:

http://www.robvanderwoude.com/amb_shortcuts.php

http://www.robvanderwoude.com/amb_shortcutsnt.php

http://www.robvanderwoude.com/shortcutinf.php

http://msdn.microsoft.com/en-us/library/ff549520.aspxOverview of INF Files

5.1.2.2     通过VB脚本创建快捷方式

shortcut.vbs:

set WshShell = WScript.CreateObject("WScript.Shell" )

set oShellLink = WshShell.CreateShortcut(WScript.Arguments.Named("shortcut") & ".lnk")

oShellLink.TargetPath = WScript.Arguments.Named("target")

oShellLink.WindowStyle = "1"

oShellLink.Arguments=WScript.Arguments.Named("args")

oShellLink.IconLocation=WScript.Arguments.Named("icon")

oShellLink.WorkingDirectory=WScript.Arguments.Named("wd")

oShellLink.HotKey=WScript.Arguments.Named("hotkey")

oShellLink.Save

參考:

http://stackoverflow.com/questions/346107/creating-a-shortcut-for-a-exe-from-a-batch-file

http://stackoverflow.com/questions/346107/creating-a-shortcut-for-a-exe-from-a-batch-file

使用演示样例:

    call %~dp0shortcut.vbs /target:"%ComSpec%" /args:"/c %~1\TOMCAT\bin\startup.bat" /shortcut:"%UserProfile%\Desktop\含能材料管理分析系统" /icon:"%~1\WEBAPP\favicon.ico" /wd:"%~1\TOMCAT\bin" /hotkey:"CTRL+SHIFT+F"

5.1.3   设计实现

将全部的文件都安装到用户指定的一个安装文件夹中。

安装程序文件夹结构:

--

│  install.bat  依据%PROCESSOR_ARCHITECTURE%跳转到合适的安装文件。

│  Readme.txt

│  unstall.bat

└─x86

    │  install.bat

    │  location.ini 安装文件夹

    │  unstall.bat

    ├─bin

    │      7z.dll

    │      7z.exe

    │      delstr.bat

    │      server.xml

    │      shortcut.vbs

    │      wmicenv.bat

    └─data

            AllInOne.sql

            dependency.txt

            JRE.7z

            PGSQL.zip

            TOMCAT.zip

            WEBAPP.7z

├─x64

│  │  install.bat

│  │  location.ini

│  │  unstall.bat

│  ├─bin

│  │      7z.dll

│  │      7z.exe

│  │      delstr.bat

│  │      server.xml

│  │      shortcut.vbs

│  │      wmicenv.bat

│  └─data

│          AllInOne.sql

│          dependency.txt

│          JRE.7z

│          PGSQL.zip

│          TOMCAT.zip

│          WEBAPP.7z

以下的代码以x86为例,x64版的是一样的。

5.1.3.1     安装脚本主流程

@echo off

set /p loc=<%~dp0location.ini

if {%loc%}=={} (

    echo 请先在location.ini中设置安装文件夹。

    goto :install_finish

)

if not exist "%loc%" (

    md "%loc%" || goto install_finish

)

(

    call :check_files & rem 检查须要安装的文件是否齐全。if exist

) && (

    call :check_already_installed "%loc%"

) && (

    call :welcome_info

) && (

    call :set_env "%loc%"  & rem call wmicenv.bat

    pause

) && (

    call :copy_files "%loc%" & rem 将文件解压到安装文件夹

) && (

    call :create_shortcut "%loc%"

    call :config_pgsql "%loc%"

) && (

    call :initialize_database "%loc%"

    call :start_tomcat "%loc%"

)

goto :install_finish

细节就省略。具体的请看代码。

5.1.3.2     问题与解决方式

n  环境变量设置不马上生效

【问题】

关于环境变量有这样一个特点:使用wmic或setx。在当前cmd实例中对环境变量作的改变。在该实例中(及其创建的子实例中,start cmd.exe)是无法获得的。

仅仅有在下一次cmd启动时生效。重新启动explorer。批处理中才干生效。

【解决方式】

所以在数据库创建时,须要使用命令的完整路径。

n  获取脚本所在文件夹

【问题】

在批处理中。须要调用当前文件夹下其他的批处理脚本(或其他文件)。假设直接写脚本名,即使与当前批处理在同一文件夹中也无效。

【解决方式】

%~dp0filename

6  附录

6.1         批处理代码

6.1.1    进度条显示工具

达到的效果:

来源:http://www.robvanderwoude.com/3rdpartybatchfiles.php#ProgressMeter

@ECHO OFF

:: Input: %1 must contain the current progress (0-100)

:: Return: None

SETLOCAL ENABLEDELAYEDEXPANSION

SET ProgressPercent=%1

SET /A NumBars=%ProgressPercent%/2

SET /A NumSpaces=50-%NumBars%

 

:: 清空之前的内容

SET Meter=

:: Note:第二FOR的最后有一个空格

FOR /L %%A IN (%NumBars%,-1,1) DO SET Meter=!Meter!I

FOR /L %%A IN (%NumSpaces%,-1,1) DO SET Meter=!Meter!

 

:: Display the progress meter in the title bar and return

TITLE Progress:  [%Meter%]  %ProgressPercent%%%

ENDLOCAL & exit /B 0  & rem 退出

6.1.2   WMIC环境变量管理工具

说明:该工具可永久性的设置系统环境变量,不会由于退出cmd而失效。

设置后在下一次cmd启动时生效,不须要重新启动操作系统。

rem @echo off

rem wmicenv.bat var-name [var-value]

rem Operate (system) environment permanently from cmd using wmic.exe

rem 參数:%1:name %2:value

setlocal

if "%~1"=="" goto wmicenv_usage

if "%~2"=="" goto delaction ELSE goto setaction

:setaction

    if not defined %~1 (

        wmic environment create name="%~1", username="<system>", variablevalue="%~2" || exit /B 1

    ) else (

        wmic environment where "name='%~1' and username='<system>'" set variablevalue="%~2" || exit /B 1

    )

    exit /B 0

:delaction

    if not defined %~1 (

        exit /B 0

    ) else (

        wmic environment where "name='%~1' and username='<system>'" delete || exit /B 1

    )

    exit /B 0

:wmicenv_usage

    echo %~n0的正确使用方式:

    echo 设置系统环境变量:%~n0 name value

    echo 删除系统环境变量:%~n0 name

exit /B 1

endlocal

6.1.3    path变量删减工具

用于从path变量中删除一个指定条目。事实上也不限于path变量,其他以’;’分隔的变量都能够。假设将for中的delims參数化。则更加灵活。

rem 功能:在一个以分号分隔的字符串集合中,删除全部等于给定字符串的元素.

rem 调用方法:call delstr.bat string-collection-seperate-by-semicolon string-delete

rem 注意: 1.源字符串以;分隔.

rem 通过变量delstr_retVal返回:失败为-1; 成功则为处理好的字符串(double-quoted)。

setlocal

    rem 删除參数的全部双引號, 检查是否为空,以及是否为之前调用失败返回的结果

    set strippedStr="%~1"

    if %strippedStr%=="" if %strippedStr%=="-1"  exit /B 1

    rem 获取(删除全部双引號),并检查第二參数是否为空

    set delStr="%~2"

    if %delStr%=="" exit /B 2

    rem 拆分源字符串。将不须要删除的条目通过retVal返回。

    :delstr_repeat

        for /f "delims=;" %%i in (%strippedStr%) do (

            if not %delStr%=="%%i" (

                if defined retVal (

                    set retVal="%retVal:~1,-1%;%%i"

                 ) else (

                    set retVal="%%i"

                 )

             )

        )

        rem 保存之前的值,不能直接用strippedstr进行比較。

        rem 由于最后一次循环时,strippedStr以两个双引號开头。

        rem 当它含有特殊字符时,会使得if或for失败

        set prestrippedStr=%strippedStr%

        rem 剪去从头開始到第一个;为止的全部字符,包括’;’

        set strippedStr="%strippedStr:*;=%

        if not %prestrippedStr:;=% EQU %prestrippedStr% goto :delstr_repeat

endlocal & (

    set delstr_retVal="%retval:~1,-1%"

    exit /B 0

)

6.2         Absurd

6.2.1   设置返回值时报错:此时不应有\ATI

【描写叙述】

报错:此时不应有 \ATI

设置返回值时,set语句假设被括号括上,而且要设置的值中有’)’时就会报错。但假设set语句不被括上括上。则没有问题。

【代码】错误代码

setlocal

    set retval=C:\Windows;C:\Program Files (x86)\ATI

    echo end

endlocal & (

    set delstr_retVal=%retval:*;=%

)

【原因】

cmd解释器。首先将变量%retval:*;=%扩展为实际值,然后才分析以下这条被扩展后的语句:

endlocal & (

    set delstr_retVal= C:\Program Files (x86)\ATI

)

由于C:\Program Files (x86)\ATI中有个右括号,把后面的字符串截断。这就使得黄色部分成为了一句。而后面的\ATI成了非法的字符串。

【正确代码】

方法一:

endlocal & set delstr_retVal=%retval:*;=%

方法二:更好

endlocal & (

    set delstr_retVal="%retval:*;=% "

)

另外一种做法更好,由于假设% retval %中有&,&&,||,<,>,>&,<&之类的命令符号时,第一种方法就会出错。

【最佳实践】

字符串处理过程中(入參、变量值、返回值、if推断,for循环。...)都须要保证使用双引號括起来。也能够在使用字符串之前做转义处理。须要转义的字符

删除以分号分隔的字符串集合中的匹配字符串

setlocal

    rem 删除參数的全部双引號, 检查是否为空,以及是否为之前调用失败返回的结果

    set strippedStr="%~1"

    if %strippedStr%=="" if %strippedStr%=="-1"  exit /B 1

    rem 获取(删除全部双引號)。并检查第二參数是否为空

    set delStr="%~2"

    if %delStr%=="" exit /B 2

    rem 拆分源字符串,将不须要删除的条目通过retVal返回。

    :delstr_repeat

        for /f "delims=;" %%i in (%strippedStr%) do (

            if not %delStr%=="%%i" (

                if defined retVal (

                    set retVal="%retVal:~1,-1%;%%i"

                 ) else (

                    set retVal="%%i"

                 )

             )

        )

        rem 保存之前的值

        set prestrippedStr=%strippedStr%

        rem 剪去从头開始到第一个;为止的全部字符,包括;

        set strippedStr="%strippedStr:*;=%

        if not %prestrippedStr:;=% EQU %prestrippedStr% goto :delstr_repeat

endlocal & (

    set delstr_retVal="%retval:~1,-1%"

    exit /B 0

)

6.2.2   explorer(资源管理器)必须重新启动。才干获得最新的环境变量

环境变量改变后。必须重新启动explorer。否则在explorer中点击运行批处理文件时,使用的是之前的环境变量。

重新启动explorer: 在任务管理器中强制杀掉全部的explorer.exe进程。

相同在任务管理器中,点击“文件->新建任务”,输入explorer并回车。

6.2.3   命令被凝视:REM凝视逻辑行

The Windows NT Command Shell:

http://technet.microsoft.com/library/cc750982.aspx#XSLTsection128121120120

依据这份文档的描写叙述,以下这行代码有问题:由于cmd是按逻辑行解释的,而rem是逻辑行凝视。所以会将后面的全部代码凝视掉。

逻辑含义

cmd实际解释

@echo off

set x=ABC

if "%X%"=="ABC" (

     rem illegal comment!

     echo "yes"

)

if "ABC"=="ABC" (rem illegal comment! echo "yes")

但经过实际測试(win7x64),没有文档上描写叙述的问题。

可能是和windows版本号有关吧。


 

6.2.4   字符串截取规则不一致

%str:~start[,end]%

字符串下标从0開始。得到的字符串,

假设start==0, 为(str[start],str[end-1]);

假设start!=0, 为(str[start], str[end])。

假设字符串中有中文。就不知道它是怎么解释的了,结果全然是乱的。

6.2.5   set中的空格会成为变量值

set var-name=var-value

1)  在等号两边不能有空格,否则var-name会被置为空。

2)  var-value之后也不能有空格,否则空格会被当作变量值。因此设置返回值时。就不能使用endlocal & set var=value & exit /B 0这种语句。而就用括号。然后换行写。

endlocal & (

    set NameAlloc.result=%timestamp%

    exit /B 0

)

6.3         命令參考

6.3.1   Escape Characters

windowsNT的保留字符:& | ( ) < > ^

以上字符假设不是在双引號中。主须要进行转义。

Escape Characters

待转义字符

转义方式

说明

%

%%

May not always be required in doublequoted strings, just try

^

^^

May not always be required in doublequoted strings, but it won't hurt

&

^&

^<

^>

|

^|

'

^'

Required only in the FOR /F "subject" (i.e. between the parenthesis), unless backq is used

`

^`

Required only in the FOR /F "subject" (i.e. between the parenthesis), if backq is used

,

^,

Required only in the FOR /F "subject" (i.e. between the parenthesis), even in doublequoted strings

;

^;

=

^=

(

^(

)

^)

!

^^!

Required only when delayed variable expansion is active

\

\\

Required only in the regex pattern of FINDSTR

[

\[

]

\]

"

\"

6.3.2   Color Code

color 背景色文字色

Code

Color

Code

Color

0

Black

8

Gray

1

Blue

9

Light Blue

2

Green

A

Light Green

3

Aqua浅绿色

B

Light Aqua

4

Red

C

Light Red

5

Purple紫红色

D

Light Purple

6

Yellow

E

Light Yellow

7

White

F

Bright White

6.3.3   Win NT内部命令

ASSOC

CALL

CHDIR/CD

CLS

COLOR

COPY

DATE

DIR

DPATH

ECHO

ENDLOCAL

ERASE/DEL

EXIT

FOR

FTYPE

GOTO

IF

MKDIR/MD

MOVE

PATH

PAUSE

POPD

PROMPT

PUSHD

REM

RENAME/REN

RMDIR/RD

SET

SETLOCAL

SHIFT

START

TIME

TITLE

TYPE

VER

6.3.4   常见环境变量

Variable

Typical value (may vary)

%COMSPEC%

C:\Windows\System32\cmd.exe

%PATH%

Varies. Includes
C:\Windows\System32\;C:\Windows\

%USERPROFILE%

C:\Users\{username}

%ALLUSERSPROFILE%

C:\ProgramData

%APPDATA%

C:\Users\(username}\AppData\Roaming

%CommonProgramFiles%

C:\Program Files\Common Files

%COMPUTERNAME%

{computername}

%HOMEDRIVE%

C: or sometimes D:

%HOMEPATH%

\Users\{username}

%LOCALAPPDATA%

C:\Users\{username}\AppData\Local

%PATHEXT%

.COM; .EXE; .BAT; .CMD; .VBS; .VBE;
.JS ; .WSF; .WSH; .MSC

%ProgramData%

C:\ProgramData

%PROGRAMFILES%

Directory containing program files, usually C:\Program Files

%ProgramFiles(x86)%

In 64-bit systems, directory containing
32-bit programs. Usually C:\Program Files (x86)

%PROMPT%

Code for current command prompt format. Code is usually $P$G

%Public%

C:\Users\Public

%SYSTEMDRIVE%

The drive containing the Windows  root directory, usually C:

%SYSTEMROOT%

The Windows root directory, usually C:\Windows

%TEMP% and %TMP%

C:\Users\{Username}
\AppData\Local\Temp

%USERNAME%

{username}

%WINDIR%

Usually C:\Windows

6.3.5   动态环境变量dynamicenvironment variables

Variable

Value

%DATE%

Current date in the format determined by the Datecommand

%TIME%

Current time in the format determined by the Timecommand

%CD%

Current directory with its full path

%ERRORLEVEL%

Number defining exit status of a previous command or program

%RANDOM%

Random number between 0 and 32767

6.3.6   WMIC其他功简单介绍

WMIC语法:

WMIC [alias] [where-clause] verbs

     alias          ::= 见以下列表

     where-clause  ::= where "property=’value’ {and|or property=’value’}"

          property   ::= 不同的alias有不同的property。

eg:环境变量有name, username...

     verbs          ::= create|delete|set|get|list...不同的功能支持的verbs不一样。

部分alias列表简单介绍:wmic有丰富的管理功能,以下仅仅列举了部分。

alias

功能描写叙述。支持的verbs(不全)

PROCESS

进程管理。call create / call terminate / delete / get / list

DATEFILE

文件管理。

list/get/call delete/call copy/call rename

FSDIR

文件夹管理。

list/get/call delete/call rename

DESKTOPMONITOR 

屏幕管理。get ScreenHeight,ScreenWidth

ENVIRONMENT

环境变量。

create/set/delete/get/list

SERVICE

服务管理。

call StartService|StopService|delete / set

USERACCOUNT

用户帐户管理。set/rename

NETUSER

网络连接管理。

6.3.7   注冊表管理:REG简单介绍

具体信息參看reg帮助。

一般形式:

REG Operation KeyName arguments

     Operation ::= 见以下的表格

     KeyName::=[\\Machine\]FullKey   ;eg: HKCU\Control Panel\International

FullKey::=ROOTKEY\SubKey

             ROOTKEY ::= [ HKLM | HKCU | HKCR | HKU | HKCC ]

             SubKey  ::= 在选择的 ROOTKEY 下的注冊表项的全名

KeyName演示样例:

HKEY_CURRENT_USER\Control Panel\International

相应的KeyName:HKCU\ControlPanel\International

Operation功能简单介绍:

Operation

arguments參数简单介绍

QUERY

/v [valueName] 查某一项值。 /s 递归子项和值;

/f value-pattern 搜索数据; /t指定查找的值类型

eg:REG QUERY "HKCU\Control Panel\International" /v sCountry 查国家信息

ADD

/v [ValueName] 值名;/t type 值类型;/d data 值的内容

eg: REG ADD HKLM\Software\MyCo /v pswd /t REG_BINARY /d fe340ead

DELETE

/v ValueName(指定值) | /ve(空名值) | /va(全部值)

/f 强行删除。不提示

eg: REG DELETE \\ZODIAC\HKLM\Software\MyCo /v MTU

删除 ZODIAC 上 MyCo 下的注冊表项 MTU

COPY

REG COPY KeyName1 KeyName2 [/s](递归复制) [/f](不提示强行复制)

eg: REG COPY HKLM\Software\MyCo\MyApp HKLM\Software\MyCo\SaveMyApp /s

批量管理

SAVE/RESTORE保存/还原LOAD/UNLOAD载入/卸载IMPORT/EXPORT导入/导出。

REG SAVE KeyName FileName [/y] | REG RESTORE KeyName FileName

REG LOAD|EXPORT KeyName FileName

REG UNLOAD KeyName

REG IMPORT FileName

COMPARE

REG COMPARE KeyName1 KeyName2 [/v ValueName | /ve] [Output] [/s]

eg: REG COMPARE HKLM\Software\MyCo\MyApp HKLM\Software\MyCo\SaveMyApp

FLAGS

值类型:

REG_SZ、REG_MULTI_SZ、REG_EXPAND_SZ 、REG_DWORD、REG_QWORD、REG_BINARY、REG_NONE

6.4         參考

http://www.robvanderwoude.com/battech.php: 这个站点很好

http://en.wikibooks.org/wiki/Windows_Batch_Scripting

http://technet.microsoft.com/library/cc750982.aspx:Windows NT Shell Scripting, Chapter2

http://www.cnblogs.com/top5/archive/2013/06/19/3143832.htmlwmic的使用



猜你喜欢

转载自www.cnblogs.com/mqxnongmin/p/10875515.html