﻿# 如何利用批次檔(Batch)讀取指令執行的結果或文字檔案內容

最近從 Visual Studio 2010 的 **建置部署套件** 功能自動產生的網站安裝批次檔中學到一個批次檔的使用技巧，他可以透過批次檔直接讀取機碼(Registry)的資訊並擷取出執行檔所在路徑，這樣一來就不用將執行檔所在的路徑寫死在批次檔裡，是非常彈性的一種方法，藉此也剛好把批次檔的 FOR 語法的使用方式給釐清一番，這樣一來以後要透過批次檔讀取或解析文字檔就更方便了。

我們先來看看這段批次檔的內容，並解釋各參數的用法，不過這種語法有點學習門檻，一定要多加思考才能融會貫通：

**注意**：在批次檔中要寫 **%i** 變數必須要寫成 **%%i** 才行，如果直接在指令列模式執行時可直接輸入 **%i**

 ![alt](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/700c8ab241b73bfa81ea-image_234.png "title")

1.  **/F** 代表要 FOR 迴圈會對傳入的字串進行解析(parsing)
2.  **"……"** 代表「選項設定」，代表 FOR 迴圈應該如何解析傳入的字串，有以下幾種選項：

1.  eol=c 用來決定斷行符號，預設為 \\n，但可換成其他字元（其中 c 只能是一個字元）  
    **註**: c 為一個字元
2.  skip=n 用來決定要先跳過幾層迴圈（也就是跳過前面幾行的意思）  
    **註**: n 為數字
3.  delims=xxx 用來決定欄位的分隔字元，預設為**空白**與**TAB符號**，並可自訂多個字元  
    **註**: xxx 代表多個字元，如果要同時設定小數點 (.) 與逗號 (,) 就要輸入 **delims=.,**
4.  tokens=x,y,m-n 用來決定一次要取出幾個欄位，第一個欄位會存放在第一個自動變數，第二個欄位會存放在第二個自動變數裡，依此類推。如果你設定第一個變數為 **%i** 那麼如果設定為 **tokens=1,2** 就代表你會得到一個 **%i** 與一個 **%j** 變數值，分別代表比對到的第1與第2個欄位。這裡有個特殊的情況是使用星號 ( \* )，如果你設定為 **tokens=1\*** 就代表你會得到一個 **%i** 變數值，以及一個 **%j** 變數值，但是 **%j** 變數值就不會再進行解析，而是將剩餘的文字全部都塞進 **%j** 變數值裡！  
    **註**: x, x, m, n 都為數字，只是 m-n 是一種特別的表示法，代表一個解析欄位的範圍。例如 tokens=2-4 就代表取得三個變數，取得第2、第3與第4個欄位的值並塞入 **%i $j %k** 變數裡
5.  usebackq 用來設定上圖編號4的語法，主要是用在執行的指令中需要包含雙引號(")的情況下，例如 for /F "usebackq" %i IN (\`dir /b "C:\\Program Files"\`) DO @echo %i

4.  **%i** 代表第一個解析出來的字串的參數代號，第一個為 **%i** 第二個為 **%j** 並依照英文字母類推
5.  小括弧裡面的就是從各管道取得的文字內容，可以讀取的內容包括三種：

1.  讀取文字檔的內容  
    for /F %i IN (sample.txt) DO echo %i
2.  字串值  
    for /F %i IN ("a b c") DO echo %i
3.  指令執行結果  
    for /F %i IN ('dir /b') DO echo %i

上面的第4點當 usebackq 有被設定的情況下會有不同的行為出現：

1.  讀取文字檔的內容 (與上述一樣)  
    for /F "usebackq" %i IN (sample.txt) DO echo %i  
    for /F "usebackq" %i IN ("C:\\My Folder\\sample.txt") DO echo %i
2.  字串值  
    for /F "usebackq" %i IN ('a b c') DO echo %i
3.  指令執行結果  
    for /F "usebackq" %i IN (\`dir /b\`) DO echo %i  
    for /F "usebackq" %i IN (\`dir /b "C:\\Program Files"\`) DO @echo %i

知道 FOR 語法如何解析文字內容後，我們就可以來分析從 Visual Studio 2010 的 **建置部署套件** 功能自動產生的網站安裝批次檔了，以下是這段批次檔的內容 (點圖可放大顯示)

[![alt](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/349e4580fda49a9bc9ca-image_thumb_30.png "title")](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/9913383c2c339d2d1965-image_235.png)

先看看執行 reg 指令的輸出為何：

[![alt](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/e207da7357493a17e719-SNAGHTML23df2e4c_thumb.png "title")](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/8c0ce4bd062b093fe4ba-SNAGHTML23df2e4c.png)

這段指令一共輸出的四行文字，第一行與最後一行都是空白，而這時我們要取得的資料是 MSDeploy 的安裝路徑，所以我們要抓取畫面上的 **C:\\Program Files\\IIS\\Microsoft Web Deploy\\** 文字。

而在 FOR 語法裡我們有用到兩個選項設定：

-   usebackq 用來讓指定輸入時可以包含雙引號(")
-   tokens=2\* 用來決從第2個欄位開始取資料，訂且在第二個自動變數填入這一行剩下的所有資料，也就是 **%i** 變數值會是第二個欄位，而 **%j** 變數值會是第三個欄位以後的所有文字

預設解析會以空白字元與 TAB 符號作為分隔字元，而我們要取得的 tokens 是從第二個欄位開始，所以當比對的文字連第二個欄位都沒有時，就會自動忽略，因此雖然我們有四行文字，但第一行與最後一行都會跳過不處理。

所以我們的迴圈會執行兩遍：

第 1 遍，在迴圈裡會取得的變數與值分別是：

-   %i = Extensions\\MSDeploy\\1
-   %j = *<空白>*

第 2 遍，在迴圈裡會取得的變數與值分別是：

-   %i = REG\_SZ
-   %j = C:\\Program Files\\IIS\\Microsoft Web Deploy\\

我們也在批次檔中看到一個 IF 判斷式：

```
if "%%~dpj" == "%%j" (
```

這個判斷是特別的地方在於 **%~dpj** 這個特殊變數，我們執行 **FOR /?** 即可取得這些特殊變數的說明：

![alt](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/f77980f6be999400bdcc-image_236.png "title")

然而 **%~dpj** 會自動將 **%j** 展開成一個完整路徑，但如果路徑本身就是「絕對路徑」的話就會保留原本的字串，而該判斷是就是利用這個特點判斷是否比對到 MSDeploy 的安裝路徑。

**相關連結**

-   [Batch files - FOR loops](http://www.robvanderwoude.com/for.php)
-   [Batch files - IF statements](http://www.robvanderwoude.com/if.php)
