批處理(bat)命令學習的一些總結(jié)

字號:


    一、set 篇:
    1、set(無開關(guān))
    set .=test
    set.
    ::若一個變量以:\.這三個與路徑相關(guān)的符號開頭,用set查看以該字符打頭的變量時可以省去一個空格。
    echo %tmp:*\=%
    ::顯示tmp變量第一個\之后的部分,其余變量替換與變量偏移太簡單不解釋
    2、set /p 變量名=注釋<設(shè)備名
    當設(shè)備名為文件時,因為文件中換行符與回車符伴生,所以只取文件第一行作為var變量的內(nèi)容,但是不超過1024字節(jié);而當設(shè)備名為nul或者com3時,只顯示不換行的注釋,這種情況下可以省略變量名(如:set /p=hello world
    3、set /a,最具技巧的命令之一
    set /a n=1,m=2
    ::同時把不同數(shù)值分別賦予兩個變量
    set /a a=b=c=d=e=f=1
    ::用一條算式為多個變量同時賦值
    set /a 1/n 2>nul||echo 變量n非純數(shù)字或為零
    ::利用分母不能為0的特征,用set判斷一個變量是否為非零純數(shù)字
    set n=1
    set /a n=!!123|!!234&!!0
    ::位運算,!、^、|和&常用于布爾運算,而邏輯位移常用于二進制運算(>>還可判斷數(shù)值是否為負,見下例)
    set /a n=-100,1/(-100>>31)||echo 變量n為負數(shù)
    ::順應(yīng)cmd中的正負數(shù)存儲特點,可以用邏輯位移實現(xiàn)判斷正負數(shù)的“布爾運算”,可以衍生出繁多的算法,比如稍加改動就可以比較兩數(shù)甚至多個數(shù)的大小
    set /a n=~-100
    ::利用~將所有二進制的1、0逆轉(zhuǎn),負號在后或在前配合可以實現(xiàn)簡單加1或減1,這個技巧主要用來減少括號的使用,因為~號與負號的優(yōu)先級都是高于算數(shù)運算符的
    set /a test=%test:~5,1%-0
    ::可以避免%test:~5,1%為空時出錯的情況
    set /a 十進制=0x十六進制,十進制=0八進制
    ::快速將十六進制與八進制數(shù)轉(zhuǎn)為十進制,可惜沒有二進制...
    :loop
    set /a n+=1001
    echo %n:~-3%
    goto loop
    ::這比常規(guī)的補位方法更優(yōu)越
    for %%a in (test 123 abc test @#$ 123) do set /a .%%a+=1
    set .|findstr /v /e =1
    ::經(jīng)典的獲取字符串的重復次數(shù)的方案
    二、for 篇:
    這是批處理中最強的內(nèi)部命令,沒有之一!
    1、for(無開關(guān))
    代碼如下:
    for %%a in (c:\*.*) do echo %%a
    ::顯示c盤根目錄下所有非隱藏、非系統(tǒng)屬性文件
    for %%a in (.\..) do echo %%~nxa
    ::顯示上一級目錄的文件夾名
    set str=123,234,345
    set str=%str:,=\%
    for %%a in (%str%\..) do echo %%~nxa
    ::用前一個技巧,巧取倒數(shù)第二段字符串,與for /f delims=\相映成趣
    for %%a in (*.txt) do (
    for /f useback delims= %%b in (%%a) do (
    set str=%%b
    for %%c in (!str:分隔符= !) do (
    for /f tokens=1* %%d in (%%c) do echo %%~d
    )
    )
    )
    ::不帶參數(shù)的for與for /f配合,威力極大,僅舉此一例
    for %%a in (123) do for %%a in (234) do for %%a in (345) do echo %%a
    ::其實如果只讀取最后一層for的參數(shù),即使多層for嵌套也可以使用同樣的參數(shù),比如%%a
    for %%z in (!tmp!) do echo !%%z!
    ::目前已知的擺脫call實現(xiàn)多層變量嵌套的最好方法,不少人用
    2、for /l
    for /l %%a in () do echo 
    ::無限循環(huán),步數(shù)為0也是一樣的效果,但是沒這個簡潔
    for /l %%a in (-4 1) do echo %%a
    ::for /l中的三項參數(shù)從左至右的三位分別是初始值、步數(shù)、終止點,當用戶給定的數(shù)量不足時,將按從右至左的順序把不足的一項賦為0
    3、for /d /r
    for /r /d %%a in (*) do echo %%a
    ::可以遍歷所有子文件夾,之所以可以聯(lián)用r開關(guān)和d開關(guān)是因為它們的參數(shù)有交集,l開關(guān)和f開關(guān)就不行了。
    4、for /f
    for /f本身的技巧并不是特別多,它的優(yōu)勢是能夠?qū)⑵渌畹妮敵鲎鳛檩斎雭矸治?,所以for /f可以說是當之無愧的內(nèi)部命令之王
    for /f tokens=* delims=0123 %%a in (0000123456) do echo %%a
    ::去除前綴的n個字符
    for /f skip=99 %%a in (1.txt) do echo 1.txt至少100行
    ::以前看到某版主寫的,印象頗深。
    for /l %%a in (1 1 10) do (
    for /f tokens=1,2* delims=\ %%a in (!tmp!) do (
    for %%c in (%%a %%b) do echo %%c
    set tmp=%%c
    )
    )
    ::將tokens的取值范圍無限拓展
    set tmp=123=234=345=456
    for /l %%a in (1 1 40) do (
    for /f tokens=1,2* delims== %%a in (!tmp!) do (
    set str=!str!,%%a,%%b
    set tmp=%%c
    )
    )
    echo %str:~1%
    ::有時候set變量替換是無法替換一些特殊字符的,此時可以用for /f處理
    set test=d:\test\
    for %%a in (test.*) do (
    if %%~za neq %%~z$test:a replace /p /u %%a %%~dp$test:a
    )
    ::判斷當前目錄下以test為名的文件是否在d:\test\文件夾下存在同名文件,如果存在且大小不同、修改日期更早,則替換之,否則不做處理。for幫助信息中的“%%~dp$path:a”參數(shù)似乎沒見人用過,雖然它的適用范圍很狹隘,但是特定的情況下不妨一試。
    setlocal enabledelayedexpansion
    set t=tmp
    set @=t
    for /f %%a in ('echo !%@%!') do echo !%%a!
    ::另一種三層嵌套方法,其實不實用。
    三、findstr 篇
    我最鐘愛的命令,可惜外部命令的啟動速度太慢,所以實際運用時較少露面。
    findstr /s /m .* *.*
    ::其實findstr也是一個dir,雖然比dir慢些,卻多了查找文件內(nèi)容的功能
    findstr /n .* 1.txt|findstr ^5000:
    ::非常實用的取指定行的方法,配合正則可以取指定范圍之內(nèi)的行
    set /p n=請輸入數(shù)字或大小寫字母
    (echo !n!)|findstr /i [0-9a-z]&&echo 輸入有誤!
    ::這個夠?qū)嵱冒??不解?BR>    dir|findstr ['-z]
    ::利用findstr和if命令中字符的實際大小順序?qū)崿F(xiàn)查找含有寬字符的行
    findstr /x .......... 1.txt
    ::查找1.txt中10字節(jié)的行
    (type 1.txt&echo;)|findstr /o .*|more +1
    ::加上for,很容易獲取1.txt每行的字節(jié)數(shù)
    findstr>1.txt /m /p .* *.*
    dir /b /a-d|findstr>2.txt /v /i /m /g:1.txt
    ::獲取含有不可打印字符的文件名,關(guān)鍵是findstr取集
    findstr ^rar! /g:1.txt
    ::此處1.txt是上個技巧的1.txt,內(nèi)容是所有含不可打印字符的文件列表,此技巧可搜索rar文件,雖然簡單,但是至今也未出錯過,原創(chuàng)。
    more>tmp +2 1.txt
    findstr>前兩行.txt /x /v /g:1.txt 2.txt
    ::有時候可用此辦法獲取前幾行,當然,絕大部分情況下沒有for /f合適,而且存在特殊字符bug
    @echo off
    findstr /n .* 1.txt>tmp1
    find /n /v 2.txt|more>tmp2 +2
    for /f tokens=2*delims=]: %%a in ('fc /n /lb10000 tmp1 tmp2^|sort') do (
    echo;%%b
    )
    del tmp?
    pause
    ::qzwqzw首創(chuàng)用fc /n同時輸出雙文本的思路,但是存在排序有可能被打亂的缺陷,所以加了個find彌補一下
    四、start、call、cmd 篇
    之所以放在一起,是因為這三個命令的功能有所交集
    1、start
    @echo off
    %1 cd.>tmp
    set /p=%1
    %1 start /b %0 :(五秒后退出) tm
    if not %1== goto %1
    set /p n=輸入任意字符
    if defined n (
    del tmp
    echo 您輸入的是%n%,五秒后退出。
    ) else echo 輸入為空!五秒后退出。
    :(五秒后退出)
    ping /n 5 localhost>nul
    if exist %2p exit
    pause
    ::妙用start /b讓set /p實現(xiàn)choice的延時功能,不知道哪位前輩首創(chuàng)的,再次贊一個。此處%1、%2的技巧僅作點綴,我只是覺得這樣“搭積木”很好玩才強加上去的。
    2、call
    set a=b
    set b=c
    call echo %%%a%%%
    ::不使用變量延遲仍然可以借助call實現(xiàn)變量的延遲讀取與嵌套,但是效率上有缺陷
    3、cmd
    set a=b
    set b=c
    cmd /c echo %%%a%%%
    ::這證明call一個命令時的效果近似于cmd /c,二者的區(qū)別體現(xiàn)在for和if這兩個命令不能用call運行,因為for和if其實可能只是關(guān)鍵字,而非真實存在的命令
    set a=b
    set b=c
    cmd /v:on /c echo !%a%!
    ::不需要setlocal,照樣可以使用變量延遲
    %1 %0 :: echo;成功調(diào)用自身
    %2
    ::個人很常用,這里用%1和%2的技巧為我所偏愛,那個::可以視情況換為rem。雖然此處并未出現(xiàn)cmd命令,但其實運行自身時執(zhí)行的就是cmd /c %0。
    @echo off
    %1 cmd /v:on /c %0 ::
    set n=123
    echo !n!
    pause
    ::綜合前兩個技巧實現(xiàn)不使用setlocal,開啟變量延遲
    @echo off
    set str=test測試1234
    setlocal enabledelayedexpansion
    for /f delims=:; %%a in ('((cmd /u /c echo !str!^)^&echo^;^;^)^|findstr /o ^;') do set /a n=%%a-5
    for /f delims=: %%a in ('((echo !str!^)^&echo^;^;^)^|findstr /o ^;') do set /a d=n-%%a+3
    set /a m=n/2,s=m-d
    echo 共!m!個字符,!d!個單字節(jié)字符、!s!個雙字節(jié)字符
    pause
    ::三步判斷單字符、雙字符個數(shù)的另類辦法。優(yōu)勢在于支持對超長字符串進行計算(此時用常規(guī)算法步驟多且難通用),缺點在于效率低。
    ren 1.exe 1.bat
    echo 請雙擊1.bat
    ::為什么這樣也可以運行呢?因為exe的打開方式是%1 %*,bat是cmd /c %1 %*,所以把exe當做bat運行時,相當于cmd /c 1.exe...不過這只適合雙擊打開,在cmd內(nèi)部調(diào)用此文件的時候是當成真正的bat運行的,所以會出錯。
    五、其他命令篇
    1、xcopy比copy強大得多,最大的遺憾在于它是外部命令
    xcopy /a 源文件夾 目標文件夾
    ::xcopy用在篩選上也很實用
    xcopy /l /y /n %cd% ..
    ::巧取當前目錄下文件的短名,并不會真的復制
    xcopy /d:1-31-2011 /l %cd% tmp\
    ::獲取修改日期在2011年1月31日以后的文件清單
    xcopy /t *.txt c:\test\
    ::復制含有txt文件的目錄結(jié)構(gòu)到c:\test
    @echo 1.txt>list
    xcopy /exclude:list ?.txt test\
    ::復制所有以單個字符為名的文件到test文件夾
    xcopy /s *.txt ..\txt\
    ::復制所有以txt為名的子文件到上一級目錄中的txt文件夾
    for /f delims= %%a in ('dir /s /b /ad^|sort -r') do rd %%a 2>nul
    ::刪除空文件夾的經(jīng)典思路,利用rd默認不刪除非空文件夾的特性進序刪除空文件夾
    for /d %%a in (*) do (
    xcopy /q /h /r /s /k %%a tmp\
    rd /s /q %%a
    ren tmp %%a
    )
    ::刪除空文件夾的另類方案
    2、相比于前面幾個大佬級的命令,這些命令算是比較不起眼的了,所以歸在一類
    copy nul+unicode.bat 解密.bat
    ::用unicode文件頭來進行編碼混淆加密的bat,可以用這條命令解密
    echo>tmp 12323412 2323242134122434 345
    more /t20 tmp>對齊.txt
    type 對齊.txt
    pause
    ::more命令的t開關(guān)也有大用途,潛規(guī)則不解釋。
    cmd /u /c echo 0123456789|more
    ::more命令會將cmd /u輸出的nul字符轉(zhuǎn)換為空格,從而實現(xiàn)逐字打印一行單字節(jié)字符。
    @echo off&setlocal enabledelayedexpansion
    set n=32768
    (for %%a in (16384 8192 4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do sort /rec !n! %0&&set /a n-=%%a||set /a n+=%%a)>nul 2>nul
    echo 最長行有%n%個字符
    pause
    ::當最長的行字符數(shù)大于128時可能可以用這個來判斷最長行的字符數(shù)(短于128時rec開關(guān)會失效,代碼中那一大堆2的n次方就是湊字數(shù)的,實戰(zhàn)中可以省掉一些),支持超長字符串,計算大文件時效率明顯優(yōu)于傳統(tǒng)算法,新折半法來自plp626的轉(zhuǎn)帖,sort的/rec開關(guān)比較雞肋,想來想去也只想到這個用途,未見先例
    ren 1.exe 1.bat
    echo 請雙擊1.bat
    ::為什么可以把exe改為bat后綴名運行呢?因為exe的打開方式是%1 %*,bat是cmd /c %1 %*,所以把exe當做bat運行時,相當于cmd /c 1.exe...不過這只適合雙擊打開,在cmd內(nèi)部調(diào)用此文件的時候是當成真正的bat運行的,所以會出錯。而且基于同樣的原因,它還可以改成com或者cmd后綴名來執(zhí)行。
    3、再介紹一些在cmd窗口中的技巧,當然它們僅僅是“欺騙”cmd窗口,一旦輸出到文件就原形畢露:
    @echo off
    echo 1
    echo 2
    echo 3
    echo 退行了
    pause>nul
    ::這個太牛了,不知道哪位發(fā)現(xiàn)的
    set dq= 
    (echo 2、計劃生育的重要性%dq%啊
    echo 1、貫徹落實科學發(fā)展觀%dq%哇)|sort
    ::借助tab鍵與退格符實現(xiàn)多行捆綁排序并錯行顯示,tab與退格之間的那個空格是關(guān)鍵,否則變?yōu)橥诵?BR>    set /p=同一行顯示不同顏色:
    set /p=紅底藍字
    echo  黃底綠字
    findstr /a:41 .* 紅底藍字?
    findstr /a:62 .* 黃底綠字?
    del>nul 紅底藍字 黃底綠字
    pause
    ::經(jīng)常見到的在同一行顯示不同顏色的辦法,不過很多人總是用    (四個退格四個空格),說明沒理解退格鍵的意義
    @prompt $_
    dir fuck.tmp
    pause
    ::利用這個prompt,打開回顯后可以同時輸出命令與命令結(jié)果,而不會有多余內(nèi)容,適合制作bat運行日志
    echo 
    ::這個黑色的圓點在前面的介紹中作為配角出現(xiàn)過,是ansi碼中的0x07,也等同于在cmd中輸入的ctrl+g,它每次被顯示在屏幕上時都會發(fā)出“滴”的一聲,所以以后findstr *.*時一定要留神了(除非不得已,否則需要把結(jié)果顯示到窗口時建議加上/p開關(guān)),萬一不小心打印出幾萬個,你的電腦會像發(fā)電報一樣響個不停,我中招n次了...
    六、cmd運行機制篇
    1、預(yù)處理機制:特殊字符優(yōu)先級、語句和語塊的劃分
    setlocal enabledelayedexpansion
    (set n=3
    set /a n=2,n=%n%+!n!+n)
    ::利用預(yù)處理機制,將一個變量解釋為多個值
    setlocal enabledelayedexpansion
    echo ^^!
    ::當語句中存在變量延遲符號時,將被預(yù)處理兩次,這是一定要注意的
    set str=.
    set str name=str
    for %%a in (%tmp%) do if defined %%a echo %%a 存在變量str
    ::利用for的參數(shù)變量在if參數(shù)劃分之后才被解釋的特點,彌補if defined對于空格變量名的兼容性缺陷,本質(zhì)原因是for和if都是特殊的函數(shù),他們的參數(shù)設(shè)置在語塊的預(yù)處理中就已經(jīng)被cmd“記住”了,之后無法對其進行改變。
    (del %0
    echo 能找到我,就給你發(fā)糖
    pause>nul)
    ::括號里的內(nèi)容被理解成一個語塊,運行其中的命令時不需從文件讀取,所以就算刪除自身仍可運行。
    echo test&pause|sort
    ::當一行命令中存在奇數(shù)個雙引號時,將會轉(zhuǎn)義其后所有本行字符
    for /f tokens^=2delims^=^ %%a in (123test456) do echo %%a
    ::通過對特殊字符的轉(zhuǎn)義,在for中用雙引號當分隔符
    for /f tokens^=2delims^=^ %%a in (^123456) do echo %%a
    set /p=^
    ::當一組字符串中含有奇數(shù)個雙引號時經(jīng)常會出錯,解決方法是轉(zhuǎn)義其中的一個,保持有效的雙引號成對,可是引號對之內(nèi)無法用轉(zhuǎn)義符對其轉(zhuǎn)義,所以轉(zhuǎn)義符要放在引號對之外使用
    set /a 1/(%random%%%2)&&set com=||set com=/f tokens=2
    for %com% %%a in (123 234 345) do echo %%a
    ::假如隨機值為偶數(shù),則顯示指定字符串第二段,否則顯示整段。這里用變量來定制命令,會比常規(guī)辦法(一條if和一條命令對應(yīng))更靈活和省事,但是要注意的是,變量延遲是在解釋語塊之后進行,所以這里的%com%不能使用變量延遲。
    set /a \test1=123,test2=234
    (@echo off
    for /f tokens=1* delims== %%a in ('set\') do echo %%b
    )|sort
    ::sort對for命令的輸出進行排序,那個@echo off并非多余,因為通道之前的若是語塊(for、if或者被成對括號包起來的語句),該語塊中的內(nèi)容將會以cmd /c的形式運行,此時的回顯是打開的,而變量延遲則是默認關(guān)閉的。
    dir /ad 123\&&md234||rd 345&tree /f|more
    ::當存在123文件夾時,創(chuàng)建234文件夾,否則刪除345文件夾,無論結(jié)果如何,接下來都會逐屏顯示當前目錄樹。重點是管道命令、邏輯連接符的靈活運用
    2、句柄的妙用
    @echo off 2>nul 3>nul
    這個命令不存在...
    echo 錯誤回顯呢?
    pause
    ::句柄備份,可用于屏蔽所有正確或錯誤回顯
    cd.>1.txt 2>2.txt 3>3.txt 4>4.txt 5>5.txt 6>6.txt 7>7.txt 8>8.txt 9>9.txt
    ::用一個命令創(chuàng)建9個文件,效率自然提高了
    @echo off
    (for /r %%a in (*.*) do del /f /s %%~nxa 3>>%%a) 2>nul 4>>%0
    pause
    ::利用寫入句柄會占用文件的特性實現(xiàn)高效刪除重復文件
    待續(xù)...