批處理腳本學習筆記
原創作品,允許轉載,轉載時請務必以超鏈接形式標明文章原始出處、作者信息和本聲明。否則將追究法律責任。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),負數表示從後往前數的位置。
|
||||||||
清空 |
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 |
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變量及命令行參數擴展功能
n 語法:
%~[options]var-name options := option{option} option := | f | d | p | n | x | s | a | t | z | $PATH: var-name := [a-zA-Z0-9] |
n 選項說明: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\ |
n 示例代碼:測試所有的變量增強功能
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 |
%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; |
%ProgramData% |
C:\ProgramData |
%PROGRAMFILES% |
Directory containing program files, usually C:\Program Files |
%ProgramFiles(x86)% |
In 64-bit systems, directory containing |
%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} |
%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的使用