BAT 批處理 基礎語法 教程 [MD]


博文地址

我的GitHub 我的博客 我的微信 我的郵箱
baiqiantao baiqiantao bqt20094 baiqiantao@sina.com

目錄

BAT 批處理教程

參考:易百教程
參考:批處理之家

當Windows為我們打開了五彩繽紛的圖形窗口的時候
DOS命中注定會隕落
CMD毫無懸念將萎縮
批處理逐漸趨向無聲無息
而powershell的到來,無疑會讓更多的人忘記批處理
這是一門即將失傳的技藝
這是一塊行將就木的領域
然而,命令行工具仍然具有批量處理一切的巨大威力
字符界面仍然是高效操作、方便靈活、簡潔快速的代名詞

基礎語法

特點

  • 批處理腳本存儲在文本文件中,其中包含的命令按順序依次執行,其功能是為了自動執行重復的命令序列
  • 批處理文件具有特殊的擴展名BAT或CMD,可以通過雙擊、或在命令提示符(cmd.exe)或在開始 - 運行行中運行
  • 批處理文件通過稱為命令解釋器的系統文件提供的接口(shell)來識別和執行,在Windows系統上是cmd.exe
  • 批處理文件可以讀取用戶的輸入,有if、for等控制結構,支持函數、數組等高級功能,支持正則表達式,可以包含其他編程代碼

編碼問題

在windows上,bat文件默認以GBK編碼格式保存(很多開發語言、環境的默認編碼為UTF-8格式),如果文件中有中文或特殊符號,強烈建議以GBK編碼格式保存,否則會因各種各樣的問題導致亂碼進而導致執行出錯!

如果不能修改文件編碼格式,例如通過 for 等命令讀寫其他編碼格式的文件,那需要使用CHCP修改編碼格式。具體可用的編碼參考 Code Page Identifiers

@echo off & CHCP 65001
:: 會在命令行中輸出【Active code page: 65001】的提示

注釋

注釋有三種:

  • Rem 注釋內容:Rem相當於命令,如果Rem的行數太多,可能會使代碼變慢
  • :: 注釋內容:建議采用這種方式的注釋
  • %注釋內容%:行內注釋
@echo off
Rem Rem注釋在未關閉命令回顯時會在屏幕顯示出來,而 :: 則什么情況下都不會顯示
echo 注釋方式三 %行內注釋%

變量

命令行參數

可以在調用批處理文件時傳遞參數,%n(n為自然數)表示在調用批處理文件時傳遞的第n個參數:

  • %0 批處理文件本身,包括完整的路徑和擴展名
  • %1 第一個參數
  • %9 第九個參數
  • %* 從第一個參數開始的所有參數

參數%0具有特殊的功能,可以調用批處理自身,以達到批處理本身循環的目的,也可以復制文件自身等等。

@echo off
echo 第一個參數為:%1

copy %0 d:\new_file.bat %最簡單的復制文件自身的方法%

set命令

set [/A] varName=value
:: 僅當該值是數值類型時,才可以使用【/A】,才能正確的進行數值計算,否則會被當做字符串進行計算
:: 使用變量的時候,變量需要包含在%符號中,如【%varName%】
set message=Hello World
echo %message%

SET /A a=5
SET /A b=10
SET /A c=%a% + %b%
echo %c%

局部與全局變量

set globalvar=默認情況下都是全局變量

SETLOCAL
set var=SETLOCAL后定義的變量只在ENDLOCAL之前有效
set globalvar=SETLOCAL后重新賦的值也只在ENDLOCAL之前有效
echo %var%
echo %globalvar%
ENDLOCAL

echo %var% %會打印:【ECHO 處於關閉狀態。】%
echo %globalvar%

環境變量

echo %JAVA_HOME%

判斷變量是否定義

SET /A a=5
SET str=包青天

if defined a echo 【變量a存在】
if not defined b echo 【變量b不存在】
if not [%1]==[] echo 【參數存在:%1】
if exist %1 echo 【文件 %1 存在】

字符串

基本操作

set message=字符串
echo 【%message%】

set var=3
set /A var=%var% + %var%
echo 定義為字符串變量后,還可以使用【/A】開關轉換為整數:%var%
:: 上面打印內容為【6】,如果不加【/A】,那么打印結果為【3 + 3】

:: 判斷字符串是否相等
if [%message%]==[字符串] echo 方式一
if %message%==字符串 echo 方式二

:: 創建一個空字符串
Set a=
if [%a%]==[] echo 檢查是否為空字符串

字符串截取

其實和其他語言的規則是一致的,截取的標准格式為:

%var:~num_chars_to_skip%
%var:~num_chars_to_skip,num_chars_to_keep%
即【%var:~fromIndex,length%】
SET a=abcd

echo 【%a:~0%】【%a:~1%】【%a:~2%】【%a:~3%】【%a:~4%】
:: 【abcd】【bcd】【cd】【d】【】
echo 【%a:~-4%】【%a:~-3%】【%a:~-2%】【%a:~-1%】
:: 【abcd】【bcd】【cd】【d】-n和4-n的效果是一樣的

echo 【%a:~0,0%】【%a:~0,1%】【%a:~0,2%】【%a:~0,3%】【%a:~0,4%】
:: 【】【a】【ab】【abc】【abcd】
echo 【%a:~0,-4%】【%a:~0,-3%】【%a:~0,-2%】【%a:~0,-1%】
:: 【】【a】【ab】【abc】【abcd】

echo 【%a:~1,1%】【%a:~1,2%】【%a:~2,1%】【%a:~3,1%】【%a:~3,2%】
:: 【b】【bc】【c】【d】【d】

替換子字符串

%str:new=old%
set str=包青天 白  乾濤 包青天
echo 【%str:包青=老%】【%str: =_%】
:: 【老天 白  乾濤 老天】【包青天_白__乾濤_包青天】

刪除子字符串

%str:subStr=%
:: 可以認為是一種特殊的替換:將指定字符替換為空
set str=包青天 白  乾濤 包青天
echo 【%str:包青=%】【%str: =%】
:: 【天 白  乾濤 天】【包青天白乾濤包青天】

if/else 語句

基本語法

  • 只有 if 語句時,if 語句的小括號是可選的
  • 有 else 語句時,if 語句必須帶小括號,而 else 語句的小括號是可選的
  • if 條件不能加小括號,否則判斷條件為 false
SET /A c=5
SET str=包青天

if %c%==5 echo 只有 if 語句時,if 語句的小括號是可選的
if %str%==包青天 (
    echo 如果換行的話必須加小括號,且左小括號不能換行--因為換行后就不是一條命令了,右括號不限制
    REM 注意:小括號內不能有 :: 格式的注釋,可以有REM格式的注釋(因為REM是命令)
)
:: 【==】既可以用來判斷數值型,也可以用來判斷字符串

if [%1]==[] (echo 呵呵) else echo 有 else 語句時,if 語句必須帶小括號,而 else 語句小括號可選
if ([%1]==[]) (echo 呵呵) else (echo if 條件不能加小括號,否則判斷條件為 false)

嵌套 if 語句

if(condition1) if (condition2) do_something
:: 只有當條件1和條件2都滿足時,才會執行 do_something 塊中的代碼

if errorlevel

環境變量 errorlevel 的初始值為0,當一些命令執行不成功,就會返回一個數值,如:1 ,2 等。

注意:IF ERRORLEVEL 是用來測試它的上一個DOS命令的返回值的,注意只是上一個命令的返回值,而且返回值必須依照從大到小次序順序判斷。

if ERRORLEVEL nubmer commend
copy %0 new_file.bat
if errorlevel 0 echo 命令成功完成

copy %0 new/file.bat
if errorlevel 1 echo 命令失敗

goto 語句

@echo off & setlocal enabledelayedexpansion
SET /A a=0

:add
set /A a+=1 & echo echo a當前的值為:%a%,a+1后的值為:!a!

if %a% LSS 3 (
    goto :add
) else (
    goto :end
)

:end
echo 執行完畢,a的值為:!a!

運算符

賦值運算符

SET /A a=3
SET /A a+=5
echo %a%
:: 其他類似的運算還有【a-=5】【a*=5】【a/=5】【a%=5】

算術運算符

SET /A a=5
SET /A b=3

SET /A c=%a%+%b%
SET /A d=%a%-%b%
SET /A e=%b%*%a%
SET /A f=%b%/%a%
SET /A g=%a%/%b%
SET /A h=%b%%%%a%
SET /A i=%a%%%%b%

echo 【%c%】【%d%】【%e%】【%f%】【%g%】【%h%】【%i%】
:: 【8】【2】【15】【0】【1】【3】【2】

關系運算符

SET /A a=5
SET /A b=10

if %a% EQU %b% echo 相等
if %a% NEQ %b% echo 不相等性
if %a% LSS %b% echo 左小於右
if %a% LEQ %b% echo 左小於等於右
if %a% GTR %b% echo 左大於右
if %a% GEQ %b% echo 左大於等於右

邏輯運算符

  • 批處理語言配備了一整套布爾邏輯運算符,如ANDORXOR,但只適用於二進制數字
  • 對於TRUEFALSE沒有任何值
  • 可用於條件的唯一邏輯運算符是NOT運算符
  • 為非二進制數字實現AND/OR運算符的方法是使用嵌套的IF條件或goto語句

邏輯非

SET /A a=5
IF NOT %a%==6 echo 邏輯非運算符NOT的使用

邏輯與

借助 if 語句實現

SET /A a=5
if %a% LSS 6 (
    if %a% GTR 4 (
        echo 嵌套if實現and的功能
    )
)
if %a% LSS 6 if %a% GTR 4 echo 嵌套if實現and的功能

借助 goto 語句實現

SET /A a=5

if not %a% LSS 6 goto end
if not %a% GTR 4 goto end
:: 為了保持和上面if的結構一致,上面是用了兩個not,實際肯定是可以不用not的
goto and_function

:and_function
echo 嵌套if實現and的功能
:end
echo end

邏輯或

邏輯或實現起來比邏輯與還要復雜一些,一般都需要借助 goto 語句來實現!

不借助 goto 語句實現的情況

這種方式只適合滿足條件時要執行的命令比較少的場景,否則會有大量的冗余代碼

SET /A a=3
IF %a% LSS 4 (
    echo 如果滿足條件一,則執行n條命令
) else IF %a% GTR 6 (
    echo 否則,如果滿足條件二,也會執行相同的n條命令
)
IF %a% LSS 4 (echo 滿足條件) else IF %a% GTR 6 (echo 滿足條件)

借助 goto 語句實現

SET /A a=5

IF %a% LSS 4 goto or_function
IF %a% GTR 6 goto or_function
goto end

:or_function
echo 嵌套if實現or的功能
:end
echo end

數組

數組類型並沒有明確定義為批處理腳本中的類型,但可以模擬出來,但是有些功能使用起來會有諸多限制。

白哥說:其實批處理腳本中的數組就是多個名稱類似的變量,其本身沒有任何特性或語法,只不過因為這些變量的格式比較像C、Java中的數組,而數組又是那么深入人心,所以我們將其當做數組來看待了而已。

數組元素

其實就是一系列相互之間沒任何關系的變量!

set a[0]=10
set a[1]=1
set a[1]=11
set a[3]=14

echo 【%a[0]%】【%a[1]%】【%a[2]%】【%a[3]%】【%a[4]%】
:: 【10】【11】【值不確定】【14】【值不確定】
:: 數組中的每個元素都需要使用set命令專門定義
:: 注意,未定義的元素的值是無法確定的,並不一定是沒有值(雖然大部分情況都是沒有defined、也沒有值的)!

數組元素下標為變量

數組元素下標為變量時,可以認為是:一個變量的名稱取決於另一個變量!

set a[0]=10
set /a k=0

:: 以下3種方式均可正確訪問 a[k]
echo %k%-%a[0]%
call echo %k%-%%a[%k%]%%
setlocal enabledelayedexpansion & echo %k%-!a[%k%]!
:: 因為a[%k%]之前並沒有定義(僅僅是定義了a[0]),所以必須`設置本地為延遲擴展`才能正常訪問,且訪問時必須使用!代替%

數組的長度

沒有直接的函數來確定數組中元素的數量,只能通過遍歷數組中的值列表手動計算

set d[0]=10
set d[1]=11
set x=0

:getArrayLength
if defined d[%x%] (
   call echo %x%-%%d[%x%]%%
   set /a x+=1
   goto :getArrayLength
)

echo 數組長度為 %x%
:: 注意,如果數組元素定義時不連續,這種方法計算出來的值可能就是錯誤的,核心在於上面的【defined】表達式

在數組中創建結構

set obj[0].Name=包青天
set obj[0].ID=66
set cur.Name=%obj[0].Name%

echo 【%obj[0]%】【%obj[0].Name%】【%cur.Name%】【%cur.ID%】
:: 【】【包青天】【包青天】【11】 cur.ID的值沒有定義,所以打印結果是不確定的

函數

函數定義

定義函數的格式

:function_name 
Do_something 
EXIT /B 0
:: EXIT語句用於確保函數正常退出

調用函數的格式

Call :function_name parameter1, parameter2… parametern
:: 需要確保在主程序中放入【EXIT /B %ERRORLEVEL%】語句,以便將主程序的代碼與函數分開

函數的基本用法

可以通過使用%~n(n代表參數的位置),來在函數內部訪問參數

親測,完全可以省略掉其中的~符號

set p=包青天
CALL :function_1
CALL :function_2 a p %p%
EXIT /B %ERRORLEVEL%

:function_1
echo 調用了【%0】函數
EXIT /B 0

:function_2
echo 調用了【%0】函數,參數為【%~1】【%2】【%3】,所有參數為【%*】
EXIT /B 0

函數的返回值

函數可以通過簡單地傳遞變量名稱來處理返回值,這些變量名稱將在調用該函數時保存返回值

CALL :function_3 c & echo 一行代碼時必須使用延遲變量【!c!】【%c%】
CALL :function_3 d
echo 不是一行代碼時兩種方式都可以【!d!】【%d%】

set p=包青天
CALL :function_3 %p% & echo 在函數中修改變量的值時,參數不是傳入變量的引用【!p!】【%p%】
CALL :function_3 p & echo 而是傳入變量的名稱【!p!】【%p%】
EXIT /B %ERRORLEVEL%

:function_3
if NOT [%1]==[] set %1=baiqiantao
EXIT /B 0

參數作為輸出參數時,此文件不要設置 setlocal enabledelayedexpansion,且函數內不要使用SETLOCAL、ENDLOCAL

函數中的局部變量

  • 函數中的局部變量可以用來避免名稱沖突,並保持函數本地的變量變化
  • 調用SETLOCAL命令后可確保命令處理器對所有環境變量進行備份,並可在調用ENDLOCAL命令后恢復
  • 當到達批處理文件結束時,即通過調用GOTO:EOFENDLOCAL被自動調用
  • 使用SETLOCAL對變量進行本地化允許在函數中自由使用變量名稱,而不必擔心與函數外使用的變量名稱沖突
  • 可以遞歸地調用一個函數,使用SETLOCAL可以確保每個級別的遞歸都使用自己的一組變量,即使變量名被重用
set x=Outer
set y=Outer
CALL :function_1 x y & echo 【!x!-!y!】--【%x%-%y%】
CALL :function_2 x y & echo 【!x!-!y!】--【%x%-%y%】
EXIT /B %ERRORLEVEL%

:function_1
set x=Inner1
set %2=Inner1
:: 當沒有SETLOCAL時,以上兩種set方式都能改變函數外的變量的值
EXIT /B 0

:function_2
SETLOCAL
set x=Inner2
set %2=Inner2
:: 當有SETLOCAL時,函數內部對變量的修改不影響函數外部的變量的值
ENDLOCAL
EXIT /B 0

2019-12-30


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM