在批處理指令碼中,預設情況下,對環境變數的更改對當前會話具有全域性影響。對於PowerShell,情況正好相反,因為作用域用於隔離指令碼的修改。在這裡,我們將探討作用域如何影響PowerShell指令碼,以及如何在它們內部和周圍工作。
在PowerShell中,“scope”指的是指令碼或命令shell正在執行的當前環境。作用域用於保護環境中的某些物件不被指令碼或函式無意中修改。特別是,除非這些命令中的引數另有規定,否則從另一個作用域執行的命令可以保護以下內容不受修改:
無論何時執行指令碼或函式,或建立新的會話或PowerShell例項,都會建立新的作用域。透過執行指令碼和函式建立的作用域與從中建立它們的作用域具有“父/子”關係。有幾個作用域具有特別特殊的含義,可以透過名稱進行訪問:
在某些命令中,作用域也可以透過數字來引用,其中當前作用域被稱為零,其祖先被遞增的整數引用。例如,在從全域性範圍執行的指令碼中,指令碼範圍將是0,全域性範圍將是1。進一步巢狀在指令碼範圍內的範圍(例如函式)將全域性範圍稱為2。但是,負數不適用於引用子作用域—其原因很快就會顯現出來。
如前所述,在一個作用域中執行的命令不會影響另一個作用域中的內容,除非明確要求這樣做。例如,如果全域性作用域中存在$MyVar,並且指令碼執行命令將$MyVar設定為不同的值,則$MyVar的全域性版本將保持不變,而$MyVar的副本將與新值一起放置在指令碼作用域中。如果$MyVar不存在,則指令碼將預設在指令碼範圍內建立它,而不是在全域性範圍內。在瞭解作用域之間的實際父/子關係時,記住這一點很重要。
PowerShell中作用域的父/子關係是單向的。命令可以檢視當前作用域、其父作用域以及該作用域之上的任何作用域,也可以修改當前作用域。但是,它們無法檢視或修改當前作用域的任何子級中的內容。這主要是因為,一旦移動到父作用域中,子作用域就已經被銷燬,因為它已經實現了它的目的。例如,在指令碼終止後,為什麼必須從全域性範圍中檢視或修改指令碼範圍中的變數?在很多情況下,您需要指令碼或函式的更改在其完成後保持不變,但在指令碼或函式的作用域中,您需要在其執行之前或之後對其物件進行更改的情況並不多。(通常,這些事情都會作為指令碼或函式本身的一部分來處理。)
當然,沒有例外的規則是什麼?上面提到的一個例外是私有作用域。專用作用域中的物件只能由在建立它們的作用域中執行的命令訪問。另一個重要的例外是具有AllScope屬性的項。這些是特殊變數和別名,任何範圍的更改都會影響所有範圍。以下命令將顯示哪些變數和別名具有AllScope屬性:
Get-Variable | Where-Object {$_.Opti*** -match 'AllScope'} Get-Alias | Where-Object {$_.Opti*** -match 'AllScope')在我們第一次瞭解作用域時,我們將從PowerShell會話開始,其中變數$MyVar被設定為字串,'我是一個全域性變數!,從命令列。然後,將從名為Scope的檔案執行以下指令碼-演示.ps1:
Function FunctionScope { 'Changing $MyVar with a function.' $MyVar = 'I got set by a function!' "MyVar says $MyVar" } '' 'Checking current value of $MyVar.' "MyVar says $MyVar" '' 'Changing $MyVar by script.' $MyVar = 'I got set by a script!' "MyVar says $MyVar" '' FunctionScope '' 'Checking final value of MyVar before script exit.' "MyVar says $MyVar" ''如果PowerShell指令碼的工作方式與批處理指令碼相同,那麼$MyVar(或批處理語法中的%MyVar%)的值將從“我是全域性變數!'到'我被劇本設定了!,最後是“我被一個函式設定了!'在再次顯式更改或會話終止之前,它將一直保留在該位置。但是,當我們遍歷每個作用域時,看看這裡實際發生了什麼——特別是在FunctionScope函式完成其工作之後,我們再次從指令碼檢查變數,然後檢查全域性作用域。
正如您所看到的,當我們在指令碼中移動時,變數似乎發生了變化,因為直到FunctionScope函式完成之前,我們都是在上次更改的同一範圍內檢查變數。但是在FunctionScope完成之後,我們又回到指令碼範圍中,$MyVar保持不變。然後,當指令碼終止時,我們返回到全域性範圍,在那裡它根本沒有被修改。
因此,這對幫助您避免意外地將更改應用到指令碼和函式之外的環境是很好的,但是如果您真的想進行這樣的修改呢?對於建立和修改超出本地範圍的物件,有一種特殊且相當簡單的語法。您只需將作用域名稱放在變數名稱的開頭,並在作用域和變數名稱之間放一個冒號。這樣地:
$global:MyVar $script:MyVar $local:MyVar在檢視和設定變數時都可以使用這些修飾符。讓我們看看這個演示指令碼會發生什麼:
Function FunctionScope { '' 'Changing $MyVar in the local function scope...' $local:MyVar = "This is MyVar in the function's local scope." 'Changing $MyVar in the script scope...' $script:MyVar = 'MyVar used to be set by a script. Now set by a function.' 'Changing $MyVar in the global scope...' $global:MyVar = 'MyVar was set in the global scope. Now set by a function.' '' 'Checking $MyVar in each scope...' "Local: $local:MyVar" "Script: $script:MyVar" "Global: $global:MyVar" '' } '' 'Getting current value of $MyVar.' "MyVar says $MyVar" '' 'Changing $MyVar by script.' $MyVar = 'I got set by a script!' "MyVar says $MyVar" FunctionScope 'Checking $MyVar from script scope before exit.' "MyVar says $MyVar" ''和前面一樣,我們將首先在全域性範圍內設定變數,然後檢查最終的全域性範圍結果。
在這裡,您可以看到FunctionScope能夠更改指令碼範圍中的變數,並在完成後保持更改。而且,對全域性範圍內變數的更改即使在指令碼退出之後仍然存在。如果您必須使用相同的程式碼重複更改指令碼內或全域性範圍內的變數,這一點尤其有用—您只需定義一個函式或指令碼,該函式或指令碼是為修改變數而編寫的,在需要的位置和方式進行修改,並在需要更改時呼叫該函式或指令碼即可。
如前所述,作用域編號也可以在某些命令中使用,以便在與本地作用域相關的不同級別修改變數。下面的指令碼與上面第二個示例中使用的指令碼相同,但是修改了函式以使用具有作用域編號的Get Variable和Set Variable命令,而不是直接引用具有命名作用域的變數:
Function FunctionScope { '' 'Changing $MyVar in scope 0, relative to FunctionScope...' Set-Variable MyVar "This is MyVar in the function's scope 0." –Scope 0 'Changing $MyVar in scope 1, relative to FunctionScope...' Set-Variable MyVar 'MyVar was changed in scope 1, from a function.' –Scope 1 'Changing $MyVar in scope 2, relative to Functi***cope...' Set-Variable MyVar 'MyVar was changed in scope 2, from a function.' –Scope 2 '' 'Checking $MyVar in each scope...' ‘Scope 0:’ Get-Variable MyVar –Scope 0 –ValueOnly ‘Scope 1:’ Get-Variable MyVar –Scope 1 –ValueOnly ‘Scope 2:’ Get-Variable MyVar –Scope 2 –ValueOnly '' } '' 'Getting current value of $MyVar.' "MyVar says $MyVar" '' 'Changing $MyVar by script.' $MyVar = 'I got set by a script!' "MyVar says $MyVar" FunctionScope 'Checking $MyVar from script scope before exit.' "MyVar says $MyVar" ''與之前類似,我們可以在這裡看到一個作用域中的命令如何修改其父作用域中的物件。
對於作用域,仍有許多工作可以完成,本文無法容納這些工作。作用域影響的不僅僅是變數,還有更多關於私有作用域和AllScope變數的知識需要學習。有關更多有用資訊,可以從PowerShell中執行以下命令:
Get-Help about_scopesTechNet上也提供了相同的幫助檔案。
Scope圖片來源:openclipart上的spadassin
... 使用Windows PowerShell和FTP下載檔案非常簡單。只需輸入ftp命令,然後使用: ...
學習程式設計的關鍵第一步是使用迴圈。謝天謝地,PowerShell將隨著您的技能不斷增長。 ...
Powershell是一個完美的方式,一個新的編碼器開始在Windows上。Powershell是命令列工具和指令碼語言的等價部分。它使您能夠透過您用來管理計算機的相同命令使計算機自動化。如果您有一個現代的Windows系統,那麼您已經有了Powershe...
檔案加密和解密可以是一個工作位。但是,使用PowerShell擴充套件,可以將程序精簡為一行命令。為此,我們需要安裝Gpg4win和Powershell模組。使用指令碼,我們可以自動化檔案加密和解密過程。 ...
大多數使用者從未聽說過PowerShell,更不用說觸控它並試用了。這可能是因為這個名字,聽起來像是隻有鐵桿IT極客才會使用的東西。或者是因為PowerShell的好處還不清楚。可能是因為最初的學習曲線。 ...
...。也有一些不同的刪除選項:使用傳統的解除安裝、使用PowerShell命令和第三方安裝程式。 ...
PowerShell是一種比命令提示符更強大的命令列shell和指令碼語言。自從Windows10釋出以來,它就成了預設的選擇,而且有很多方法可以開啟它。 PowerShell的使用更為複雜,但它比命令提示符更加健壯和強大。這就是為什麼它成為高階...