共用方式為


關於解析

簡短描述

描述 PowerShell 如何剖析命令。

完整描述

當您在命令提示字元中輸入命令時,PowerShell 會將命令文字分成一系列稱為 標記的區段,然後決定如何解譯每個令牌。

例如,如果您輸入:

Write-Host book

PowerShell 會將命令分成兩個令牌,Write-Hostbook,並使用兩個主要剖析模式之一獨立解譯每個令牌:表達式模式和自變數模式。

備註

當 PowerShell 剖析命令輸入時,它會嘗試將命令名稱解析為 Cmdlet 或原生可執行檔。 如果命令名稱沒有完全匹配,PowerShell 會將命令作為默認動詞添加到 Get- 前面。 例如,PowerShell 會將 Process 剖析為 Get-Process。 基於下列原因,不建議使用此功能:

  • 效率不佳。 這會導致PowerShell多次搜尋。
  • 首先解析具有相同名稱的外部程式,因此不能執行預期的 cmdlet。
  • Get-HelpGet-Command 無法辨識無動詞名稱。

表達式模式

表達式模式是用於結合運算式,這是在腳本語言中進行值操作的必要功能。 表達式是PowerShell語法中值的表示法,而且可以是簡單或複合的,例如:

字面表達式是其值的直接表示法:

'hello'
32

變數表示式會包含它們所參考之變數的值:

$x
$script:path

運算子將其他運算式結合起來以進行計算:

-12
-not $Quiet
3 + 7
$input.Length -gt 1
  • 字串常值 必須包含在引號中。
  • 數字 會被視為數值,而不是一系列字元(除非轉義)。
  • 運算子,包括一元運算符,例如 --not,以及 +-gt等二元運算符,都會解譯為運算符,並在其自變數上套用各自的運算(操作數)。
  • 屬性和轉換表示式 被解析為表示式並應用於從屬表示式,例如 [int] '7'.
  • 變數引用 將計算為其值,但禁止 展開 (即粘貼預填充的參數集),並會導致解析器錯誤。
  • 其他任何內容都將被視為要調用的命令。

自變數模式

剖析時,PowerShell 會先將輸入解譯為表達式。 但是當遇到命令調用時,解析會繼續在參數模式下進行。 如果您有包含空格的自變數,例如路徑,則必須以引號括住這些自變數值。

自變數模式是針對殼層環境中的命令剖析自變數和參數所設計。 除非輸入使用下列其中一個語法,否則所有輸入都會被視為可展開的字串:

  • 美元符號 ()$ 後跟變數名稱開始變數引用,否則將解釋為可擴展字串的一部分。 變數參考可以包含成員存取或索引。

    • 在簡單變數參考之後的其他字元,例如 $HOME,會被視為相同參數的一部分。 將變數名稱括在大括號 ({}) 中,將它與後續字元分開。 例如: ${HOME}
    • 當變數引用包括成員訪問時,任何其他字元中的第一個字元被視為新參數的開頭。 例如,$HOME.Length-more 會產生兩個自變數:$HOME.Length 的值和字串常值 -more
  • 字串以引號('")開始

  • 大括號({})開啟新的腳本區塊

  • 逗號 (), 引入以數位形式傳遞的清單,但要調用的命令是本機應用程式時除外,在這種情況下,它們將被解釋為可擴展字串的一部分。 不支援首字母、連續逗號或尾隨逗號。

  • 括弧 (()) 開始新的表達式

  • 子表達式運算子($())會開啟嵌入表達式

  • 初始@符號(@)開始表示式語法,例如splatting(@args)、陣列(@(1,2,3))及哈希表常值(@{a=1;b=2})。

  • 在令牌的開頭若有 ()$()@(),則會建立一個可包含表達式或巢狀命令的新解析上下文。

    • 後面接著其他字元時,第一個額外的字元會被視為新的個別自變數的開頭。
    • 當前面有未加引號的文本時,其 $() 工作方式類似於可擴展字元串, () 啟動一個作為表達式的新參數,並 @() 被視為作為文本 @ ,並 () 啟動一個作為表達式的新參數。
  • 除了仍然需要轉義的元字符之外,其他所有內容都會被視為可展開的字串。

    • 自變數模式元字元(具有特殊語法意義的字元)是:<space> ' " ` , ; ( ) { } | & < > @ #。 在這些中,< > @ # 只有在標記開頭才具有特別性。
  • 停止剖析標記(--%)會變更所有剩餘參數的解析。 如需詳細資訊,請參閱下方的停止解析標記 一節。

範例

下表提供數個在表達式模式和自變數模式中處理的令牌範例,以及這些令牌的評估。 在這些範例中,變數 $a 的值是 4

範例 模式 結果
2 表現 2 (整數)
`2 表現 “2” (命令)
Write-Output 2 表現 2 (整數)
2+2 表現 4 (整數)
Write-Output 2+2 論點 “2+2” (字串)
Write-Output(2+2) 表現 4 (整數)
$a 表現 4 (整數)
Write-Output $a 表現 4 (整數)
$a+2 表現 6 (整數)
Write-Output $a+2 論點 “4+2” (字串)
$- 論點 “$-” (指令)
Write-Output $- 論點 “$-” (string)
a$a 表現 “a$a” (命令)
Write-Output a$a 論點 “a4” (字串)
a'$a' 表現 “a$a” (命令)
Write-Output a'$a' 論點 “a$a” (字符串)
a"$a" 表現 “a$a” (命令)
Write-Output a"$a" 論點 “a4” (字串)
a$(2) 表現 “a$(2)” (命令)
Write-Output a$(2) 論點 “a2” (字串)

每個權杖都可以解釋為某類物件型別,例如 布爾值字串。 PowerShell 會嘗試從表達式判斷物件類型。 物件類型取決於命令預期的參數類型,以及 PowerShell 是否知道如何將自變數轉換成正確的類型。 下表顯示指派給表達式所傳回值的數個型別範例。

範例 模式 結果
Write-Output !1 引數 “!1” (字串)
Write-Output (!1) 運算式 假(布爾值)
Write-Output (2) 運算式 2 (整數)
Set-Variable AB A,B 引數 'A','B'(陣列)
CMD /CECHO A,B 引數 'A,B' (字串)
CMD /CECHO $AB 運算式 'A B' (陣列)
CMD /CECHO :$AB 引數 ':A B' (字串)

將參數傳遞至原生指令

從 PowerShell 執行原生命令時,PowerShell 會先剖析自變數。 剖析的自變數接著會聯結成單一字串,每個參數都以空格分隔。

例如,下列命令會呼叫 icacls.exe 程式。

icacls X:\VMS /grant Dom\HVAdmin:(CI)(OI)F

若要在 PowerShell 2.0 中執行此命令,您必須使用逸出字元來防止 PowerShell 錯誤解譯括號。

icacls X:\VMS /grant Dom\HVAdmin:`(CI`)`(OI`)F

停止解析令牌

從 PowerShell 3.0 開始,您可以使用 停止解析--%) 令牌來防止 PowerShell 將輸入解析為命令或表達式。

備註

停止解析令牌僅適用於 Windows 平臺。

呼叫原生命令時,請將停止剖析令牌放在程式參數之前。 這項技術比使用逸出字元來避免誤解要容易得多。

當遇到停止解析符號時,PowerShell 會將行中的其餘字元視為文字。 它執行的唯一解譯是替代使用標準 Windows 表示法的環境變數值,例如 %USERPROFILE%

icacls X:\VMS --% /grant Dom\HVAdmin:(CI)(OI)F

PowerShell 會將下列命令字串傳送至 icacls.exe 程式:

X:\VMS /grant Dom\HVAdmin:(CI)(OI)F

停止剖析令牌只有在遇到下一個換行符或管線字元之前才有效。 不能使用延續字元 ()` 來擴展其效果,也不能使用命令分隔符 (); 來終止其效果。

除了環境變數引用之外 %variable% ,您不能在命令中嵌入任何其他動態元素。 不支援將 % 字元轉義為 %%,就像在批處理檔中執行的方式一樣。 %<name>% 代碼標籤總是展開。 如果不 <name> 引用定義的環境變數,則令牌將通過 as-is傳遞。

您不能使用流重定向(如 >file.txt),因為它們是作為參數逐字傳遞給 target 命令的。

傳遞包含引號字元的參數

某些原生命令需要包含引號字元的自變數。 一般而言,PowerShell 的命令行剖析會移除您提供的引號字元。 剖析的自變數接著會聯結成單一字串,每個參數都以空格分隔。 然後,這個字串會指派給 物件的Arguments 屬性 ProcessStartInfo 。 字串內的引號必須使用額外的引號或反斜杠 (\) 字元逸出。

備註

PowerShell 不會將反斜杠 ()\ 字元識別為轉義字元。 它是底層 API ProcessStartInfo.Arguments用於的轉義字元。

如需逸出需求的詳細資訊,請參閱 ProcessStartInfo.Arguments 的檔

以下是使用該工具 TestExe.exe 的範例。 PowerShell 源儲存庫中的 Pester 測試使用此工具。 這些範例的目標是將目錄路徑 "C:\Program Files (x86)\Microsoft\" 傳遞至原生命令,使其接收路徑做為引號字串。

參數會將接收的值顯示為可執行檔的自變數。 您可以使用此工具來確認您已正確逸出自變數中的字元。

TestExe -echoargs """""${env:ProgramFiles(x86)}\Microsoft\\"""""
TestExe -echoargs """""C:\Program Files (x86)\Microsoft\\"""""
TestExe -echoargs "\""C:\Program Files (x86)\Microsoft\\"""
TestExe -echoargs --% "\"C:\Program Files (x86)\Microsoft\\"
TestExe -echoargs --% """C:\Program Files (x86)\Microsoft\\""
TestExe -echoargs --% """%ProgramFiles(x86)%\Microsoft\\""

所有範例的輸出都相同:

Arg 0 is <"C:\Program Files (x86)\Microsoft\">

您可以從原始程式碼建置 TestExe。 請參閱 TestExe

將自變數傳遞至 PowerShell 命令

從 PowerShell 3.0 開始,您可以使用 端參數 令牌 (--) 來停止 PowerShell 將輸入解譯為 PowerShell 參數。 這是 POSIX 殼層和公用程式規格中指定的慣例。

參數結尾標記 (--) 表示之後的所有自變數都會以實際形式傳遞,就像將雙引號放在它們周圍一樣。 例如,使用 -- 您可以輸出字串 -InputObject,而不使用引號或將其解譯為參數:

Write-Output -- -InputObject
-InputObject

不同於停止剖析(--%)令牌,-- 令牌後面的任何值都可以由 PowerShell 解譯為表達式。

Write-Output -- -InputObject $env:PROCESSOR_ARCHITECTURE
-InputObject
AMD64

此行為僅適用於PowerShell命令。 如果您在呼叫外部命令時使用 -- 令牌,-- 字串會當做自變數傳遞給該命令。

TestExe -echoargs -a -b -- -c

輸出顯示 -- 會當做自變數傳遞至 TestExe

Arg 0 is <-a>
Arg 1 is <-b>
Arg 2 is <-->
Arg 3 is <-c>

另請參閱