批處理——感嘆號和變數延遲擴充套件
先來說說變數延遲擴充套件吧。當然,放狗一搜,就能看到滿天飛的關於變數延遲擴充套件的文章,所以,我這裡就簡單介紹一下。先來看一段批處理:
set str=test
if %str%==test (
set str=another test
echo %str%
)
上面的程式碼段極其簡單,給str賦值,判斷其值是否為test,如果是,重新賦值為another test,再顯示str的值。
作為正常人的思維,這裡顯示的肯定是another test了,但其實不是,其顯示的仍然是test,這是為什麼?因為:windows在解釋執行此程式碼段時,在遇到if語句後的括號後,只把它當一條語句處理而不是兩條語句,所以,在第二條語句中的%str%會被替換成它目前的值test,上面的程式碼相當於下面的程式碼的效果:
set str=test
if %str%==test (
set str=another test
echo test ::注意這裡
)
所以,輸出自然是test了。
這樣程式設計的靈活性就大大降低了,於是,M$就想了一個workground的方法,那就是變數延遲,很簡單,看如下程式碼:
@echo off setlocal enabledelayedexpansion ::注意這裡 set str=test if %str%==test ( set str=another test echo !str! ::注意這裡 echo %str% ::區別 )
現在會輸出什麼呢?試一下就知道,第一行輸出another test,第二行輸出test。
現在解釋一下,setlocal enabledelayedexpansion用於開啟變數延遲,這是告訴直譯器,在遇到複合語句的時候,不要將其作為一條語句同時處理,而仍然一條一條地去解釋。但是這時必須用!str!來引用變數,如果仍然用%str%引用是不起作用的。
好了,變數延遲擴充套件解釋完了,至少這就是我知道的變數延遲擴充套件。
=========================== 我是自豪的分割線,如果你只想知道變數延遲擴充套件是怎麼回事,看到這裡就OK了 ===========================
今天變數延遲擴充套件和感嘆號讓我蛋疼了半天,所以現在也要來扯扯它們的蛋。
試試以下程式碼段:
@echo off
setlocal enabledelayedexpansion
set str=test!!!
echo %str%
開啟變數延遲,給str賦值,輸出str,於是,輸出自然是test!!!了。但其實,windows告訴我們,又錯了,輸出是test,感嘆號被windows吃了。
當然如果註釋掉開啟變數延遲那一行,這幾行是可以正常工作的,所以說是開啟變數延遲影響了我們正常的工作,但我至今還沒搞清楚為什麼會這樣,這隻有M$知道。
於是,關閉變數延遲吧,可是程式又需要使用變數延遲來實現一些邏輯,怎麼辦?兩個辦法:
1.暫時關閉變數延遲:
@echo off
setlocal enabledelayedexpansion
:: do something here
setlocal disabledelayedexpansion ::關閉變數延遲
set str=test!!!
echo %str%
setlocal enabledelayedexpansion
:: continue...
在需要處理感嘆號的地方,暫時關閉變數延遲,處理完後再開啟。這時能正常輸出感嘆號。
2.在開啟變數延遲之前set:
@echo off
set str=test!!!
setlocal enabledelayedexpansion
echo !str! ::注意這裡
在開啟變數延遲之前設定好變數,但是要注意,在使用變數的時候,需要使用感嘆號引用。這時感嘆號也可以正常輸出。
最後貼一段為什麼讓我蛋疼的程式碼(變數延遲自然是開啟的):
set server=%~1
set username=%~2
set password=%~3
echo %date%, %time% [INFO] Report server address: [%server%], username: [%username%], password: [*******]
rs.exe -i "PublishReports.rss" -s "%server%" -u "%username%" -p "%password%" -l 600
為了不回顯password,我輸出了一大串*。在我機器上測試時,我的password字元都很常規,所以通過。但是,QA的password裡面有感嘆號。。。
關鍵的是,這裡呼叫的是M$的Report Server的rs.exe來上傳模板,它丟擲一個Could not connect的exception,於是,我自然地想到是report server的service出了問題,但查了好久也沒發現report server有什麼問題。。。誰TMD會想到是別人的password裡有感嘆號,誰TMD又會想到是跟所謂延遲變數的衝突導致的,更有誰會想到,我自己自作聰明地為了不顯示password而顯示出了一大串hard code的星號導致看不到password的值。。。