Batch 溫故/知新
YiPo
2015-06-30
1
前言
• 最近 自動化 正如火如荼進行。
nuuobuild_2005.bat, copy_testload.bat, Debug_Install.bat,
SkinEncrypt.bat, CopySkinEncryptFiles.bat, …
• 把事情一件件寫下來 (成 .bat),電腦替你做。
• 其實蠻瑣碎而缺乏規則的,
建議多查 (/?)、多試 (寫小程式),再三確認。
我不直接回答你 用例子回答你
2
總覽
• @ECHO OFF
• 各式符號用途
• Argument/Return
• 變數兩型
• IF 三招
• FOR 四式
• 註解
• Block
• Function
• 其他討論
• 衍生閱讀
3
Hello World (in Batch)
SET /P NAME=Name:
ECHO Hello, %Name%!
C:UsersYiPo>SET /P NAME=Name:
Name: YiPo
C:UsersYiPo>ECHO Hello, YiPo!
Hello, YiPo!
真的像電腦在
一行行幫你輸入指令。
• 方便 debug
• 但也有點囉嗦
名詞:prompt, echo
• SET 其實是設定環境變數,
若加上 /P 可由 stdin 取得資料。
• % 來 展開 環境變數 (不是 $)。
4
@ECHO OFF (1)
@SET /P NAME=Name:
@ECHO Hello, %Name%!
Name: YiPo
Hello, YiPo!
作用於該行
不顯示 prompt 與 echo
5
@ECHO OFF (2)
ECHO OFF
SET /P NAME=Name:
ECHO Hello, %Name%!
C:UsersYiPo>ECHO OFF
Name: YiPo
Hello, YiPo!
執行後生效
不顯示 prompt 與 echo
6
@ECHO OFF (3)
@ECHO OFF
SET /P NAME=Name:
ECHO Hello, %Name%!
Name: YiPo
Hello, YiPo!
@ECHO OFF 就是這樣來的。
(不同於 bash 的 #!/bin/bash
7
符號總動員
@ 該行不 echo
% 展開變數
重新導向
< 從檔案輸入
<&n 輸入至該 fd
> 輸出至檔案
>&n 輸出該 fd 至
| 管線
指令串接
& (無條件) 串連指令
&& 前面成功才執行
|| 前面失敗才執行
() 巢狀指令
續行:^
跳脫字元
^% ^& ^| ^( ^) ^^
0: stdin
1: stdout
2: stderr
8
Input/Output 與 Argument/Return
@ECHO OFF
ECHO %0, %*
ECHO %1, %2, %3
SHIFT
ECHO %1, %2, %3
EXIT /B 56
C:UsersYiPoExample.bat, apple banana cat dog
apple, banana, cat
banana, cat, dog
C:UsersYiPo>Example.bat apple banana cat dog
• %0 至 %9,沒有 %10 該怎麼辦?
• EXIT 蠻難用的,
無法跳出單層 batch。
小祕訣:可以用拖拉方式餵檔案路徑給 .bat。
9
變數兩型
• %X (只能一個字元)
– 指令參數 (%0-%9)、迴圈變數 (%A-%Z, %a-%z)
– %~X (FOR /?)
• %VAR%
– 環境變數
– %VAR:~1,-1% 或 %VAR:str1==str2% (SET /?)
10
%1 "foo bar.txt" 原始內容
%~1 foo bar.txt 除去引號
%~f1 C:UsersYiPofoo bar.txt 絕對路徑
%~d1 C: • 磁碟代號
%~p1 UsersYiPo • 路徑
%~n1 foo bar • 檔名
%~x1 .txt • 副檔名
%~s1 C:UsersYiPoFOOBAR~1.TXT 8+3
%~a1 --a------ 檔案屬性
%~t1 2015-06-29 11:30 修改日期
%~z1 240 檔案大小
11
IF 三招
• IF ERRORLEVEL 3
– exit code >= 3
• IF foo == bar
– 陷阱很多
• IF EXIST file
所以要從大的挑到小的。
12
陷阱:小心 空變數 與 空白字元 (1)
SET VAR=
IF %VAR% == foo (
ECHO OK
)
這個時候不應有 (。
IF == foo (
SET VAR=foo bar
IF _%VAR% == _foo (
ECHO OK
)
這個時候不應有 bar。
IF _foo bar == _foo (
IF _ == _foo ( IF "foo bar" == foo (
13
陷阱:小心 空變數 與 空白字元 (2)
SET VAR=foo bar
IF "%VAR%"=="foo bar" (
ECHO OK
)
OK
IF "foo bar" == "foo bar" (
SET VAR="foo bar"
IF "%VAR%"=="foo bar" (
ECHO OK
)
這個時候不應有 bar""=="foo
bar"。
IF ""foo bar""=="foo bar" (
快不行了…只有 %~1 可以去引號算是正解了
正正解:IF "%~1"=="foo" ( 14
FOR 四式
FOR … %%I IN (…) DO …
• FOR 清單 (空白分隔的變數)
• FOR /D, FOR /R 檔案 (遞迴)
• FOR /L 數數字
• FOR /F 資料剖析
在 .bat 裡要才 %%
15
應用例:從一加到十
SET SUM=0
FOR /L %%I IN (1,1,10) DO (
SET /A SUM+=%%I
)
ECHO %SUM%
55
(begin, step, end)
SET /A 還能夠算數喔!
16
應用例:讀取設定檔
FOR /F %%I IN (config.ini) DO SET %%I
ECHO apple=%apple%, banana=%banana%, cherry=%cherry%
apple=1, banana=8, cherry=3
config.ini
apple = 1
banana = 8
cherry = 3
17
陷阱:延遲環境變數展開 (需 CMD /V:ON)
SET SUM=0
FOR /L %%I IN (1,1,10) DO (
SET /A SUM+=%%I
ECHO %SUM%
)
0
0
0
0
0
0
0
0
0
0
!SUM!
1
3
6
10
15
21
28
36
45
55
18
註解
• REM
– 標準做法
– (過去有 |, >, < 的陷阱)
• ::
– 其實是 GOTO 標籤
– 不能加在行尾
19
Block
SETLOCAL
SET VAR=I'm a local variable.
ECHO VAR=%VAR%
ENDLOCAL
ECHO VAR=%VAR%
VAR=I'm a local variable.
VAR=
20
Function
CALL :func apple banana cherry
ECHO OK
GOTO :EOF
:func
ECHO %*
GOTO :EOF
apple banana cherry
OK
小心別繼續往下執行
21
利用一下 PATH 與 CD
22
SET TARGET_PATH=D:TestloadODMDlink...
%TOOLS_PATH%CabArc.exe %TARGET_PATH%file1 ...
%TOOLS_PATH%NuGuidPatch.exe %TARGET_PATH%file2 ...
%TOOLS_PATH%SkinEncrypt.exe %TARGET_PATH%file3 ...
CD /D %~dp0
PATH tools
CabArc file1 ...
NuGuidPatch file2 ...
SkinEncrypt file3 ...
使用前都要手動改這行
很長一串,不易閱讀。
更多討論
• PATH 變數內,路徑即使有空白字元也不能加雙引號。
• SET ERRORLEVEL 令 %ERRORLEVEL% 不如往常。
• 含空白字元的字串串接小祕訣
這樣也行:C:"Program Files"Java
• Windows 其實支援 symbolic link 了 (MKLINK /?)
C:ProgramDataOracleJavajavapath 是為一例
• 在 Makefile 裡,指令不能是大寫。
23
衍生閱讀
• 善用 Command /?
– HELP 看支援的指令;SET 看可用的環境變數。
• Rob van der Woude’s Scripting Pages
http://www.robvanderwoude.com/batchfiles.php
• PowerShell
Windows 下一代的腳本語言
24

Batch 溫故/知新

  • 1.
  • 2.
    前言 • 最近 自動化正如火如荼進行。 nuuobuild_2005.bat, copy_testload.bat, Debug_Install.bat, SkinEncrypt.bat, CopySkinEncryptFiles.bat, … • 把事情一件件寫下來 (成 .bat),電腦替你做。 • 其實蠻瑣碎而缺乏規則的, 建議多查 (/?)、多試 (寫小程式),再三確認。 我不直接回答你 用例子回答你 2
  • 3.
    總覽 • @ECHO OFF •各式符號用途 • Argument/Return • 變數兩型 • IF 三招 • FOR 四式 • 註解 • Block • Function • 其他討論 • 衍生閱讀 3
  • 4.
    Hello World (inBatch) SET /P NAME=Name: ECHO Hello, %Name%! C:UsersYiPo>SET /P NAME=Name: Name: YiPo C:UsersYiPo>ECHO Hello, YiPo! Hello, YiPo! 真的像電腦在 一行行幫你輸入指令。 • 方便 debug • 但也有點囉嗦 名詞:prompt, echo • SET 其實是設定環境變數, 若加上 /P 可由 stdin 取得資料。 • % 來 展開 環境變數 (不是 $)。 4
  • 5.
    @ECHO OFF (1) @SET/P NAME=Name: @ECHO Hello, %Name%! Name: YiPo Hello, YiPo! 作用於該行 不顯示 prompt 與 echo 5
  • 6.
    @ECHO OFF (2) ECHOOFF SET /P NAME=Name: ECHO Hello, %Name%! C:UsersYiPo>ECHO OFF Name: YiPo Hello, YiPo! 執行後生效 不顯示 prompt 與 echo 6
  • 7.
    @ECHO OFF (3) @ECHOOFF SET /P NAME=Name: ECHO Hello, %Name%! Name: YiPo Hello, YiPo! @ECHO OFF 就是這樣來的。 (不同於 bash 的 #!/bin/bash 7
  • 8.
    符號總動員 @ 該行不 echo %展開變數 重新導向 < 從檔案輸入 <&n 輸入至該 fd > 輸出至檔案 >&n 輸出該 fd 至 | 管線 指令串接 & (無條件) 串連指令 && 前面成功才執行 || 前面失敗才執行 () 巢狀指令 續行:^ 跳脫字元 ^% ^& ^| ^( ^) ^^ 0: stdin 1: stdout 2: stderr 8
  • 9.
    Input/Output 與 Argument/Return @ECHOOFF ECHO %0, %* ECHO %1, %2, %3 SHIFT ECHO %1, %2, %3 EXIT /B 56 C:UsersYiPoExample.bat, apple banana cat dog apple, banana, cat banana, cat, dog C:UsersYiPo>Example.bat apple banana cat dog • %0 至 %9,沒有 %10 該怎麼辦? • EXIT 蠻難用的, 無法跳出單層 batch。 小祕訣:可以用拖拉方式餵檔案路徑給 .bat。 9
  • 10.
    變數兩型 • %X (只能一個字元) –指令參數 (%0-%9)、迴圈變數 (%A-%Z, %a-%z) – %~X (FOR /?) • %VAR% – 環境變數 – %VAR:~1,-1% 或 %VAR:str1==str2% (SET /?) 10
  • 11.
    %1 "foo bar.txt"原始內容 %~1 foo bar.txt 除去引號 %~f1 C:UsersYiPofoo bar.txt 絕對路徑 %~d1 C: • 磁碟代號 %~p1 UsersYiPo • 路徑 %~n1 foo bar • 檔名 %~x1 .txt • 副檔名 %~s1 C:UsersYiPoFOOBAR~1.TXT 8+3 %~a1 --a------ 檔案屬性 %~t1 2015-06-29 11:30 修改日期 %~z1 240 檔案大小 11
  • 12.
    IF 三招 • IFERRORLEVEL 3 – exit code >= 3 • IF foo == bar – 陷阱很多 • IF EXIST file 所以要從大的挑到小的。 12
  • 13.
    陷阱:小心 空變數 與空白字元 (1) SET VAR= IF %VAR% == foo ( ECHO OK ) 這個時候不應有 (。 IF == foo ( SET VAR=foo bar IF _%VAR% == _foo ( ECHO OK ) 這個時候不應有 bar。 IF _foo bar == _foo ( IF _ == _foo ( IF "foo bar" == foo ( 13
  • 14.
    陷阱:小心 空變數 與空白字元 (2) SET VAR=foo bar IF "%VAR%"=="foo bar" ( ECHO OK ) OK IF "foo bar" == "foo bar" ( SET VAR="foo bar" IF "%VAR%"=="foo bar" ( ECHO OK ) 這個時候不應有 bar""=="foo bar"。 IF ""foo bar""=="foo bar" ( 快不行了…只有 %~1 可以去引號算是正解了 正正解:IF "%~1"=="foo" ( 14
  • 15.
    FOR 四式 FOR …%%I IN (…) DO … • FOR 清單 (空白分隔的變數) • FOR /D, FOR /R 檔案 (遞迴) • FOR /L 數數字 • FOR /F 資料剖析 在 .bat 裡要才 %% 15
  • 16.
    應用例:從一加到十 SET SUM=0 FOR /L%%I IN (1,1,10) DO ( SET /A SUM+=%%I ) ECHO %SUM% 55 (begin, step, end) SET /A 還能夠算數喔! 16
  • 17.
    應用例:讀取設定檔 FOR /F %%IIN (config.ini) DO SET %%I ECHO apple=%apple%, banana=%banana%, cherry=%cherry% apple=1, banana=8, cherry=3 config.ini apple = 1 banana = 8 cherry = 3 17
  • 18.
    陷阱:延遲環境變數展開 (需 CMD/V:ON) SET SUM=0 FOR /L %%I IN (1,1,10) DO ( SET /A SUM+=%%I ECHO %SUM% ) 0 0 0 0 0 0 0 0 0 0 !SUM! 1 3 6 10 15 21 28 36 45 55 18
  • 19.
    註解 • REM – 標準做法 –(過去有 |, >, < 的陷阱) • :: – 其實是 GOTO 標籤 – 不能加在行尾 19
  • 20.
    Block SETLOCAL SET VAR=I'm alocal variable. ECHO VAR=%VAR% ENDLOCAL ECHO VAR=%VAR% VAR=I'm a local variable. VAR= 20
  • 21.
    Function CALL :func applebanana cherry ECHO OK GOTO :EOF :func ECHO %* GOTO :EOF apple banana cherry OK 小心別繼續往下執行 21
  • 22.
    利用一下 PATH 與CD 22 SET TARGET_PATH=D:TestloadODMDlink... %TOOLS_PATH%CabArc.exe %TARGET_PATH%file1 ... %TOOLS_PATH%NuGuidPatch.exe %TARGET_PATH%file2 ... %TOOLS_PATH%SkinEncrypt.exe %TARGET_PATH%file3 ... CD /D %~dp0 PATH tools CabArc file1 ... NuGuidPatch file2 ... SkinEncrypt file3 ... 使用前都要手動改這行 很長一串,不易閱讀。
  • 23.
    更多討論 • PATH 變數內,路徑即使有空白字元也不能加雙引號。 •SET ERRORLEVEL 令 %ERRORLEVEL% 不如往常。 • 含空白字元的字串串接小祕訣 這樣也行:C:"Program Files"Java • Windows 其實支援 symbolic link 了 (MKLINK /?) C:ProgramDataOracleJavajavapath 是為一例 • 在 Makefile 裡,指令不能是大寫。 23
  • 24.
    衍生閱讀 • 善用 Command/? – HELP 看支援的指令;SET 看可用的環境變數。 • Rob van der Woude’s Scripting Pages http://www.robvanderwoude.com/batchfiles.php • PowerShell Windows 下一代的腳本語言 24