Windows PowerShell 講座(4)—變數
發佈日期: 2008 年 2 月 19 日
**作者:**賴榮樞
www.goodman-lai.idv.tw
如同一般的程式語言,Windows PowerShell 也提供了數種存放資料的方式,而變數是其中基本且常用的方式。本文將說明 Windows PowerShell 所提供的變數功能,包括變數的型別、轉換、宣告、內建變數,以及處理變數的 cmdlet。
變數名稱
變數型別
型別轉換
資料型別
宣告變數型別
變數都是物件
內建變數
處理變數的 cmdlet
總結
變數是預留給程式存放資料的記憶體空間,現代的高階程式語言都能自行處理記憶體空間配置的細節,不需開發者介入,開發者只需要瞭解 Windows PowerShell 變數的特性,即可直接使用變數(雖然 Windows PowerShell 提供了 New-Variable cmdlet 來宣告並指定變數初值,但未事先宣告亦可使用變數)。
說明變數之前,還記得我們在上一篇文章《Windows PowerShell 講座(3)—PS磁碟機》提過專門用來存放變數的 PS 磁碟機 variable:,以下的指令可以列出目前 Windows PowerShell 環境裡的「所有」變數例子(就算您尚未宣告或自訂任何變數,一執行 Windows PowerShell 之後,就有許多內建的變數):
dir variable:
Windows PowerShell 規定變數名稱的第一個字元必須是$符號,而其他的字元可以混合英文字母、中文字元、數字和底線符號;雖然變數名稱也可以使用底線以外的任何符號,但就必須以大括號抓住變數名稱。Windows PowerShell 還有許多內建變數(本文後續將會說明),因此您的變數名稱最好不要與這些內建變數重複;此外,變數名稱是不分大小寫,因此以下前三個變數實際上是同一個變數:
$CompanyName $companyName $companyname # 只要以大括號括住, # Windows PowerShell的變數名稱可以使用任何字元 ${My Variable Name--@@--}
Windows PowerShell 的變數除了可以用在指令碼程式,也可以用在文字操作模式。Windows PowerShell 的變數在未指定變數值之前,都是 Variant 的物件型別,但是指定了型別或變數值之後,變數的子型別就會有所改變。例如在 Windows PowerShell 文字操作模式輸入:
$a="3" $b="4" $a+$b
最後會顯示 34,是因為我們指定給這兩個變數的值,都以雙引號括住 (也可以用單引號括住),這等於是將這兩個變數指定成字串型別,而加號對字串型別的資料是連接運算子,因此運算結果會是 34。使用 Windows PowerShell 的變數不需特意指定型別,當我們將變數值指定給變數時,Windows PowerShell 會自動依照變數值的型別,賦予變數型別。再舉一例,如果上述改成以下,結果就會是7,因為以下兩個變數值是整數,因此加號會進行加法運算:
$a=3 $b=4 $a+$b
如果以加號處理字串和整數型別的變數,結果會是如何呢?嗯,這要看加數的型別是字串還是整數。例如以下三個例子的結果大不相同,我們先假設有以下幾個變數:
$a="3" $b=4 $c="SS"
$a + $b:是字串加整數,而且 Windows PowerShell 可以將 4 轉換成字串型別,因此會對兩個變數進行字串連接而得到 34。
$b + $a:是整數加字串,而且 Windows PowerShell 可以將 "3" 轉換成整數型別,因此會對兩個變數進行算術相加而得到7。
$b + $c:也是整數加字串,但是 Windows PowerShell 無法將 "SS" 轉換成整數型別,因此會出現格式錯誤的訊息。
$c + $b:雖然也是字串加整數,但與上例不同的是,Windows PowerShell 可以將 4 轉換成字串型別,因此會對兩個變數進行字串連接而得到 SS4。
變數型別的轉換除了交給 Windows PowerShell 自動處理,您也可以自行指定轉換的型別,例如:
[int]$a + $b:由於在 $a 之前加了 [int],等於是在運算時強制將字串 "3" 轉換成整數 3,因此會對兩個變數進行算術相加而得到 7。
[string]$b + $a:在$b之前加了 [string],等於是在運算時強制將整數4轉換成字串 "4",因此會對兩個變數進行字串連接而得到 43。
[string]$b + $c:在 $b 之前加了 [string],等於是在運算時強制將整數 4 轉換成字串 "4",因此會對兩個變數進行字串連接而得到 4SS。請注意,就算在 $c 之前加上 [int],還是無法強制將字串SS轉換成整數 SS,因此還是會出現格式錯誤的訊息。
由於 Windows PowerShell 的變數也都是物件,擁有許多方法可供叫用,而如果想要知道變數的型別,可以利用其中的 GetType 方法取得變數的型別資訊,或者再加上 Name 屬性,即可直接列出型別名稱。例如:
$a.GetType() $b.GetType().Name
Windows PowerShell 的資料型別相當多樣,因為 Windows PowerShell 的基底是 .NET Framework,因此兩者的資料型別是相通的,但為了方便表示,Windows PowerShell 已經將常用的資料型別名稱另外設定了別名,例如 int 或 int32 是 System.Int32、double 是System.Doule、string 是 System.String 的別名。以下列出的是常用的資料型別:
[adsi] |
AD 服務物件 |
[array] |
陣列 |
[bool] |
布林值 (True 或 False) |
[byte] |
8 位元無號整數 |
[char] |
單一個 Unicode 字元(16位元) |
[datetime] |
日期或時間 |
[decimal] |
128 位元十進位值 |
[double] |
倍精度 64 位元浮點數 |
[hashtable] |
雜湊表物件 |
[int] 或 [int32] |
32 位元有號整數 |
[long] |
64 位元有號整數 |
[regex] |
規則運算式 |
[single] |
單精度 32 位元浮點數 |
[scriptblock] |
程式區塊 |
[string] |
固定長度的 Unicode 字串 |
[WMI] |
WMI 執行個體或集合 |
[WMIclass] |
WMI 類別 |
[xml] |
Xml 物件 |
之前變數的例子都未指定型別,因此 Windows PowerShell 會依據變數值的型別,自動轉換變數型別,而且會動態改變型別;例如以下的例子:
這個例子分別將整數、字串、小數等三種型別的值指定給變數 $Age,並且在指定之後利用 $Age.GetType().Name 檢視此變數的型別,您會發現變數型別也的確隨著變數值動態變成 Int32、String、Double。
不過這種看似方便的功能,實際上可能因為使用的疏忽而出現與預期不符的型別,以及不易察覺的錯誤結果。因此,越大、越複雜的程式,建議應該要自行宣告變數型別,以免因為 Windows PowerShell 自動轉換型別而造成預期之外的結果。
若要宣告變數型別,可以如下方式指定其型別及初值,例如以下的例子會將變數 $Age 的型別宣告成整數 [int],並且設定初值為 18:
[int]$Age=18
這時如果再將 19、"Cathy"、"20" 指定給變數 $Age,會有什麼樣的結果呢?如下圖。
將數值 19 指定給變數 $Age 的結果一如我們的預期,變數值因而變成 19,變數型別依然是 Int32。然而將字串 "Cathy" 指定給變數卻出現了格式不正確的錯誤訊息,這正是因為我們已經先將變數 $Age 宣告成 Int32 型別所致。最後又將字串 "20" 指定給變數 $Age,但結果是否出乎您意料?不僅沒有出現錯誤訊息,而且經由檢查發現變數 $Age 的型別依然是 Int32,但是變數值變成 20 了。
再如以下的例子:
我們先宣告了字串型別的變數 $var,但將其初值指定為整數值 77,檢查其變數型別是為 String。隨後再分別將浮點數和 DateTime 型別資料指定給變數 $var,並檢查變數 $var 的型別,可以發現資料指定給變數時,若資料與變數的型別不符,Windows PowerShell 會「盡量」將資料型別自動轉換成變數的型別。
變數都是物件,是 Windows PowerShell 最大的特點。例如本文之前曾經利用以下的方式找出變數的型別,就是叫用變數(這種物件)的 GetType 方法,這個方法會傳回變數的 Type 物件,而 Type 物件的 Name 屬性值則是型別名稱:
[int]$Age=18 $Age.GetType() $Age GetType().Name
變數就是物件,讓變數的處理添加了許多彈性與便利,除了上述以 GetType 方法得知變數型別之外,每種型別的變數還有許多不同的方法和屬性。我們可以利用 Get-Member 得知變數擁有的方法和屬性,例如以下的指令可以顯示上述字串變數 $Company 和整數變數 $Age 的方法和屬性;以下兩個圖分別是執行結果:
$Age | Get-Member $Company | Get-Member
從以上兩個圖可以發現,整數和字串型別的變數物件,各有共同和不同的方法、屬性,例如之前示範過的 GetType 是兩者共同的方法,而整數變數物件的 ToString 方法可以將整數值轉換成字串、字串變數物件的 Length 屬性值是該字串的長度(這些方法或屬性的詳細用法,可以從 .NET Framework 的說明檔查到);例如以下的例子會將字串變數 $Company 的長度指定到整數變數 $CmpyLen:
[int]$CmpyLen=$Company.Length
管理者除了可以自訂變數來用,Windows PowerShell 還提供了許多內建的變數,這類的變數分成自動變數和環境變數兩類,儲存著系統或 Windows PowerShell 環境的相關資訊。以下兩個表格列出了這兩類變數及簡述。
$$ |
內含 Windows PowerShell 最後一次接收到的內容的最後一個指令(也就是您最後一次輸入到 Windows PowerShell 並按下 Enter 按鍵的內容的最後一個指令)。 |
$? |
如果最後一次的指令操作是成功的,其值是 True,否則是 False。 |
$^ |
內含 Windows PowerShell 最後一次接收到的內容的第一個指令(也就是您最後一次輸入到 Windows PowerShell 並按下 Enter 按鍵的內容的第一個指令)。 |
$_ |
內含目前用在指令碼區塊、過濾器、陳述式裡的管線物件。 |
$Args |
內含傳給函式的參數陣列。 |
$ConfirmPreference |
指定 Windows PowerShell 完成有副作用的動作之前要先作什麼。 |
$ConsoleFileName |
目前主控台檔案的名稱。 |
$DebugPreference |
指定在指令碼程式裡以 Write-Debug 寫入資料,或在 cmdlet 或提供者以 WriteDebug 寫入資料的動作。 |
$Error |
指定執行 cmdlet 但發生錯誤的相關資訊,為物件型別。 |
$ErrorActionPreference |
指定在指令碼程式裡以 Write-Error 寫入資料,或在 cmdlet 或提供者以 WriteError 寫入資料的動作。 |
$ErrorView |
指定顯示錯誤的模式。 |
$ExecutionContext |
指定可用於 cmdlet 的執行物件。 |
$False |
布林值 False。 |
$FormatEnumerationLimit |
指定 IEnumerable 物件列舉值的界限。 |
$foreach |
foreach 迴圈的列舉值。 |
$Home |
使用者的家資料夾 (home directory),相當於 %homedrive%%homepath%。 |
$Host |
內含目前 Windows PowerShell 的資訊。 |
$Input |
用在管線中間的指令碼區塊。 |
$LASTEXITCODE |
內含最後一個 Win32 執行檔直行結果的結束碼。 |
$MaximumAliasCount |
內含目前這個 Windows PowerShell 階段最大可用的別名數量。 |
$MaximumDriveCount |
內含最大可用的磁碟數量 (但不含底層作業系統所提供)。 |
$MaximumErrorCount |
內含最大可用的錯誤數量。 |
$MaximumFunctionCount |
內含目前這個 Windows PowerShell 階段最大可用的函式數量。 |
$MaximumHistoryCount |
內含命令歷程項目的最大數量。 |
$MaximumVariableCount |
內含目前這個 Windows PowerShell 階段最大可用的變數數量。 |
$MaximumAliasCount |
內含目前這個 Windows PowerShell 階段最大可用的別名數量。 |
$MyInvocation |
包含指令碼如何叫用的資訊。 |
$NestedPromptLevel |
Windows PowerShell 提示的巢狀階層,最外層為 0。 |
$null |
NULL 值。 |
$OFS |
用在陣列轉換成字串的輸出欄位分隔器,預設是空白字元。 |
$PID |
Windows PowerShellprocess.$pi 的行程 ID 值。 |
$Profile |
使用者設定檔 (profile.ps1) 的位置。 |
$ProgressPreference |
指定 progress 記錄送出後的動作 |
$PsHome |
安裝 Windows PowerShell 的資料夾名稱。 |
$PWD |
目前工作資料夾。 |
$ReportErrorShowExceptionClass |
若設為 True,當顯示類別名稱時,會輸出例外的類別名稱。預設值是 False。 |
$ReportErrorShowInnerException |
若設為 True,會輸出內部例外的完整串鏈,每個例外訊息會縮排成額外的階層,並且由此列出的剩餘選項所格式化。預設值為 False。 |
$ReportErrorShowSource |
若設為 True,會顯示例外來源的組件名稱。預設值為 True。 |
$ReportErrorShowStackTrace |
若設為 True,會輸出例外的堆疊追蹤。預設值為 False。 |
$ShellId |
Windows PowerShell 殼層執行的名稱 (預設是 Microsoft.PowerShell)。 |
$ShouldProcessPreference |
指定 ShouldProcess 用在 cmdlet 的動作。 |
$ShouldProcessReturnPreference |
ShouldPolicy 的傳回值。 |
$StackTrace |
內含最後一次錯誤的詳細堆疊追蹤資訊。 |
$True |
布林值 True。 |
$VerbosePreference |
指定在指令碼程式裡以 Write-Verbose 寫入資料,或在 cmdlet 或提供者以 WriteVerbose 寫入資料的動作。 |
$WarningPreference |
指定在指令碼程式裡以 Write-Warning 寫入資料,或在 cmdlet 或提供者以 WriteWarning 寫入資料的動作。 |
$WhatIfPreference |
指定 -whatif 是否要對所有的命令有作用。 |
我們在上一篇文章《Windows PowerShell 講座(3)—PS磁碟機》提過專門用來放置環境變數的 PS 磁碟機 env:,;例如以下的例子:
# dir 是 Get-Childitem 的別名 # 顯示所有環境變數名稱及值 dir env: # 顯示 Path 環境變數及值 dir env:path # 顯示 SystemRoot 環境變數及值 dir env:systemroot
如果想要個別使用 Windows PowerShell 所提供的環境變數,可以利用下列的語法:
$env:<環境變數名稱>;
例如以下的例子:
# 使用 Path 環境變數 $env:path
FakePre-ee37efeec99649b39ebf434e5b9a9e54-2764c235d2584b3cb6da9922cf4e5b45
環境變數值也可以利用下列語法更改:
$env:<環境變數名稱>; = <變數值>;
例如以下兩個例子都是在現有的 Path 環境變數值加上 c:\MyMSH:
$env:path = $env:path + ";c:\MyMSH" set-item -path env:path -value ($env:path + ";c:\MyMSH ")
為了方便變數的處理,Windows PowerShell 也提供了一組 cmdlet,以下本文將討論這些 cmdlet 的用法,但要先請留意的是,這些 cmdlet 裡的變數名稱都不需要加上 $ 符號。
New-Variable (別名為 nv) 都可以用來建立變數,如果欲建立的變數已存在,會產生錯誤。例如以下的例子:
# 建立變數 rtYu,但未指定值 nv rtYu # 建立變數 Age,其值為整數 18 nv age -value 18 # 建立變數 Company,其值為字串 Microsoft nv Company -value "Microsoft"
Set-Variable (別名為 set) 可以用來指定變數值,如果欲指定值的變數不存在,會自動建立該變數。例如以下的例子:
# 建立變數 Company,其值為字串 Microsoft set Company -value "Microsoft"
Get-Variable (別名是 gv) 可以用來取得已經建立的變數,例如以下的例子取得上例建立的兩個變數:
Clear-Variable (別名是 clv) 可以用來清除變數值,例如以下的例子會清除上例建立的兩個變數值:
Remove-Variable (別名為 rv) 可以用來刪除變數,例如以下的例子會清除上例建立的兩個變數 (因此以 gv 取回變數會產生找不到變數的錯誤訊息):
以 .NET Framework 為基礎的 Windows PowerShell,所提供的變數功能與 .NET Framework 也有許多相通之處,例如資料型別以及變數即物件等,尤其是後者有助於變數的處理。此外,Windows PowerShell 也提供了一組專門處理變數的 cmdlet,以及為數眾多的內建變數。不過,關於變數的範圍,本文將留待論及函式時,再一併討論。