901
技術社區[雲棲]
由batch 命令setlocal enabledelayedexpansion引發的
預告:先來一段長長的嘮叨!
作為一名比較能折騰的初級程序員,對一切都充滿了好奇心,強迫症是個比較流行的詞,我想我也應該是中毒份子吧。
這幾天在公司折騰環境,一直用的是ubuntu,很好很強大,但是用上兩個顯示屏後就變得特別慢(絕對無法忍受),ubuntu10.10後一直采用的事unity桌麵,後來在google上發現原來是個bug(https://bugs.launchpad.net/ubuntu/+source/unity/+bug/769650),無奈,解決方案也不好,於是轉向gnome,gnome3我不喜歡,感覺不方便,ubuntu10.04采用的gnome2才是王道,google後發現gnome2這個項目已經死了(嗚嗚~~),不過開源世界總是有你想不到的,一個新的項目mate繼續開發gnome2,很happy,安裝方式也很簡單,見https://wiki.mate-desktop.org/download。曬一下
左麵寫程序,右麵看文檔,爽多了!
---------------------------------------------很高興你能看到華麗的分割線,下麵進入正題--------------------------------------------------------------------------------------------------------------------------
在電腦變快之後,裝上了vb,然後想裝個綠色版qq,網上JayXon的應該是最普及的,他這裏麵有個bat文件,以前也沒想著去打開看看,今天突發奇想打開看了看,發現是個很神奇(其實是micorsoft比較笨吧)的代碼:
SetLocal EnableDelayedExpansion網上發現這叫延遲環境變量擴展,很奇怪的名字,這是什麼回事呢,google一番後發現是這麼回事:
batch文件在執行時,解釋器會把先把一整條命令讀入,然後分析語法是否正確,這在單句是沒有任何問題的,但是bat文件中的if、for等這些符合語句(符合也算一個語句)就有問題了,下麵我一一以代碼演示之。下麵的代碼寫在C:\hello.bat文件中,讀者可以copy自行實踐之。
@echo off set foo="helloworld" echo %foo%
上麵是很簡單的單句賦值情況,程序能夠程序正確輸出helloworld
下麵看看如果是if語句會怎麼樣呢?
@echo off set foo="helloworld" if %foo%=="helloworld" ( set foo="helloubuntu" echo %foo% )這時程序會輸出什麼呢?不了解batch文件的人肯定說是helloubuntu了,但是事實卻還是helloworld,這是為什麼呢?
現在我請你換下身份,以batch解釋器而不是程序員的思路來看這個腳本到底是怎麼執行的:
1.首先,解釋器看到if後知道這條語句是個符合語句,那麼他會讀取一個完整句子後在進行後麵的語法驗證、執行(讀整個句子時並不執行)等操作
2.讀完整個句子後,解釋器會進行一項變量擴展(也就是我們熟知的變量替換)的工作,batch特有的語法是兩個%之間的變量(上麵的%foo%就是)會被替換
3.完成替換工作後,解釋器開始執行這個整句。
在上麵3個過程後,解釋器看到的是這樣的代碼:
@echo off set foo="helloworld" if %foo%=="helloworld" ( set foo="helloubuntu" echo "helloworld" )所以,這麼一看,輸出helloworld一點也不奇怪了。
為了加深大家的理解,我在給一個for的例子
@echo off for /L %%i in (1,1,10) do ( set foo=%%i echo %foo% )這會輸入什麼呢,看看結果

為什麼會這樣呢?讀者可以試著吧編譯器看到的結果自己寫出來,其實也很簡單
@echo off for /L %%i in (1,1,10) do ( set test=%%i echo )就是這樣的嘛,那麼為什麼會是上麵的信息呢,這裏你需要了解echo命令的用法,如果你隻輸入一個echo,後麵不跟任何參數,那麼將輸出echo的狀態

通過echo的幫助文檔我們可以很清楚的了解,同時對於batch能夠識別的命令都能夠用類似的語法獲得
因為我們第一行的@echo off將echo的狀態給關閉了,所以輸入了如上的信息。
到現在位置我們已經知道了batch解釋器在解釋符合語句時的問題了,那麼微軟時如何解決的呢,其實我們自己想想也很好相出辦法解決,你一行行的讀入不就行了嘛,幹嘛非要讀入符合語句的整句。其實微軟也是這麼做的,這就是本文標題命令的由來了,不過這是為了要用!變量名!的形式來引用了。
我們這次把上麵的兩個例子加上setlocal enabledelayedexpansion再試試看:
首先是if的情況
@echo off setlocal enabledelayedexpansion set foo="helloworld" if %foo%=="helloworld" ( set foo="helloubuntu" echo !foo! )

for的那個例子:
@echo off setlocal enabledelayedexpansion for /L %%i in (1,1,10) do ( set foo=%%i echo !foo! )

結果和我們預想的一樣了。
最後更新:2017-04-03 14:54:11
上一篇:
[Qt教程] 第47篇 進階(七) 定製Qt幫助係統
下一篇:
常見麵試之機器學習算法思想簡單梳理
bitmap 設置圖片尺寸,避免 內存溢出 OutOfMemoryError的優化方法
LiveVideoStackCon 2017 打造最專業的音視頻技術大會
Django 博客開發教程 13 - 已知小問題修正
java異常中Exception捕獲不到的異常
Red Hat開源其Hadoop存儲係統
與MySQL傳統複製相比,GTID有哪些獨特的複製姿勢?
覓房於東山舉行高層管理會議,下半年又將布署哪些動作?
webview可以獲取網頁源碼,進行重新排版嗎
JUNIT在線API以及 assertTrue(boolean condition),assertTrue(String message, boolean condition)
C# ToString()格式化時間,常用模式