当前位置:网站首页 > 更多 > 玩电脑 > 正文

[玩转系统] 关于解析

作者:精品下载站 日期:2024-12-14 02:20:50 浏览:14 分类:玩电脑

关于解析


简短描述

描述 PowerShell 如何解析命令。

详细描述

当您在命令提示符处输入命令时,PowerShell 将命令文本分解为一系列称为“令牌”的段,然后确定如何解释每个令牌。

例如,如果您输入:

Write-Host book

PowerShell 将命令分解为两个标记:Write-Hostbook,并使用两种主要解析模式之一独立解释每个标记:表达式模式和参数模式。

笔记

当 PowerShell 解析命令输入时,它会尝试将命令名称解析为 cmdlet 或本机可执行文件。如果命令名称不完全匹配,PowerShell 会在命令前面添加 Get- 作为默认动词。例如,PowerShell 将 Service 解析为 Get-Service。不建议使用该功能,原因如下:

  • 这是低效的。这会导致 PowerShell 进行多次搜索。
  • 首先解析具有相同名称的外部程序,因此您可能无法执行预期的 cmdlet。
  • Get-HelpGet-Command 无法识别无动词名称。
  • 命令名称可以是保留字或语言关键字。 Process 两者兼而有之,并且无法解析为 Get-Process

表达方式

表达式模式用于组合表达式,这是脚本语言中值操作所需的。表达式是 PowerShell 语法中值的表示形式,可以是简单的也可以是复合的,例如:

文字表达式是其值的直接表示:

'hello'
32

变量表达式携带它们引用的变量的值:

$x
$script:path

运算符组合其他表达式进行求值:

-12
-not $Quiet
3 + 7
$input.Length -gt 1
  • 字符串文字必须包含在引号中。
  • 数字被视为数值而不是一系列字符(除非转义)。
  • 运算符,包括--not等一元运算符以及+-gt 等二元运算符 被解释为运算符并对其参数(操作数)应用各自的运算。
  • 属性和转换表达式被解析为表达式并应用于从属表达式。例如:[int] '7'
  • 变量引用将被评估为其值,但splatting被禁止并导致解析器错误。
  • 其他任何内容都被视为要调用的命令。

论证模式

解析时,PowerShell 首先将输入解释为表达式。但是,当遇到命令调用时,解析会以参数模式继续。如果您的参数包含空格(例如路径),则必须将这些参数值括在引号中。

参数模式旨在解析 shell 环境中命令的参数和参数。所有输入都被视为可扩展字符串,除非它使用以下语法之一:

  • 美元符号 ($) 后跟变量名称开始变量引用,否则它将被解释为可扩展字符串的一部分。变量引用可以包括成员访问或索引。

    • 简单变量引用后面的附加字符(例如 $HOME)被视为同一参数的一部分。将变量名称括在大括号 ({}) 中,以将其与后续字符分隔开。例如,$ {HOME}
  • 当变量引用包含成员访问时,任何附加字符中的第一个字符将被视为新参数的开始。例如,$HOME.Length-more 会产生两个参数:$HOME.Length 的值和字符串文字-more
  • 引号('")开始字符串

  • 大括号 ({}) 开始新的脚本块

  • 逗号 (,) 引入作为数组传递的列表,除非被调用的命令是本机应用程序,在这种情况下它们将被解释为可扩展字符串的一部分。不支持开头、连续或结尾逗号。

  • 括号 (()) 开始一个新表达式

  • 子表达式运算符 ($()) 开始嵌入表达式

  • 初始 at 符号 (@) 开始表达式语法,例如 splatting (@args)、数组 (@(1,2,3))、和哈希表文字 (@{a=1;b=2})。

  • 标记开头的 ()$()@() 创建一个新的解析上下文,其中可以包含表达式或嵌套命令。

    • 当后跟附加字符时,第一个附加字符被视为新的单独参数的开始。
  • 当前面带有不带引号的文字 $() 时,其工作方式类似于可扩展字符串,() 启动一个作为表达式的新参数,而 @() 被视为文字 @,其中 () 开始一个新的表达式参数。
  • 除了仍然需要转义的元字符之外,其他所有内容都被视为可扩展字符串。请参阅处理特殊字符。

    • 参数模式元字符(具有特殊语法意义的字符)为: <space> ' " ` , ; ( ) { } | & @ #。其中, < > @ # 仅在标记的开头是特殊的。
  • 停止解析标记 (--%) 更改所有剩余参数的解释。有关更多信息,请参阅下面的停止解析标记部分。

  • 示例

    下表提供了在表达式模式和参数模式下处理的标记的几个示例以及这些标记的评估。对于这些示例,变量 $a 的值为 4

    Example Mode Result 2 Expression 2 (integer) `2 Expression "2" (command) Write-Output 2 Expression 2 (integer) 2+2 Expression 4 (integer) Write-Output 2+2 Argument "2+2" (string) Write-Output(2+2) Expression 4 (integer) $a Expression 4 (integer) Write-Output $a Expression 4 (integer) $a+2 Expression 6 (integer) Write-Output $a+2 Argument "4+2" (string) $- Argument "$-" (command) Write-Output $- Argument "$-" (string) a$a Expression "a$a" (command) Write-Output a$a Argument "a4" (string) a'$a' Expression "a$a" (command) Write-Output a'$a' Argument "a$a" (string) a"$a" Expression "a$a" (command) Write-Output a"$a" Argument "a4" (string) a$(2) Expression "a$(2)" (command) Write-Output a$(2) Argument "a2" (string)

    每个标记都可以解释为某种对象类型,例如布尔字符串。 PowerShell 尝试根据表达式确定对象类型。对象类型取决于命令期望的参数类型以及 PowerShell 是否知道如何将参数转换为正确的类型。下表显示了分配给表达式返回值的类型的几个示例。

    Example Mode Result Write-Output !1 argument "!1" (string) Write-Output (!1) expression False (Boolean) Write-Output (2) expression 2 (integer) Set-Variable AB A,B argument 'A','B' (array) CMD /CECHO A,B argument 'A,B' (string) CMD /CECHO $AB expression 'A B' (array) CMD /CECHO :$AB argument ':A B' (string)

    处理特殊字符

    反引号字符 (`) 可用于转义表达式中的任何特殊字符。这对于转义要用作文字字符而不是元字符的参数模式元字符最有用。例如,要使用美元符号 ($) 作为可扩展字符串中的文字:

    "The value of `$ErrorActionPreference is '$ErrorActionPreference'."
    
    The value of $ErrorActionPreference is 'Continue'.
    

    线路延续

    反引号字符也可以用在行尾,以便您在下一行继续输入。这提高了采用多个具有长名称和参数值的参数的命令的可读性。例如:

    New-AzVm `
        -ResourceGroupName "myResourceGroupVM" `
        -Name "myVM" `
        -Location "EastUS" `
        -VirtualNetworkName "myVnet" `
        -SubnetName "mySubnet" `
        -SecurityGroupName "myNetworkSecurityGroup" `
        -PublicIpAddressName "myPublicIpAddress" `
        -Credential $cred
    

    但是,您应该避免使用续行。

    • 反引号字符可能很难看到并且很容易忘记。
    • 反引号后的额外空格会中断行的延续。由于空间很难看到,因此很难发现错误。

    PowerShell 提供了多种在语法中的自然点换行的方法。

    • 在管道字符 (|) 之后
    • 在二元运算符之后(+--eq 等)
    • 数组中逗号 (,) 之后
    • 打开[{(等字符后

    对于较大的参数集,请使用splatting。例如:

    $parameters = @{
        ResourceGroupName = "myResourceGroupVM"
        Name = "myVM"
        Location = "EastUS"
        VirtualNetworkName = "myVnet"
        SubnetName = "mySubnet"
        SecurityGroupName = "myNetworkSecurityGroup"
        PublicIpAddressName = "myPublicIpAddress"
        Credential = $cred
    }
    New-AzVm @parameters
    

    将参数传递给本机命令

    从 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 开始,您可以使用 stop-parsing (--%) 令牌来阻止 PowerShell 将输入解释为 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> 未引用已定义的环境变量,则令牌将按原样传递。

    您不能使用流重定向(如 >file.txt),因为它们作为参数逐字传递给目标命令。

    在以下示例中,第一步运行命令而不使用停止解析标记。 PowerShell 计算带引号的字符串并将值(不带引号)传递给 cmd.exe,这会导致错误。

    PS> cmd /c echo "a|b"
    'b' is not recognized as an internal or external command,
    operable program or batch file.
    PS> cmd /c --% echo "a|b"
    "a|b"
    

    笔记

    使用 PowerShell cmdlet 时不需要停止解析令牌。但是,将参数传递给 PowerShell 函数可能很有用,该函数旨在使用这些参数调用本机命令。

    传递包含引号字符的参数

    某些本机命令需要包含引号字符的参数。 PowerShell 7.3 更改了解析命令行以获取本机命令的方式。

    警告

    新行为是对 Windows PowerShell 5.1 行为的重大更改。这可能会破坏调用本机应用程序时解决各种问题的脚本和自动化。使用停止解析标记 (--%) 或 Start-Process cmdlet 以避免在需要时传递本机参数。

    新的 $PSNativeCommandArgumentPassing 首选项变量控制此行为。该变量允许您选择运行时的行为。有效值为 LegacyStandardWindows。默认行为是特定于平台的。在 Windows 平台上,默认设置为 Windows,非 Windows 平台默认为 Standard

    Legacy 是历史行为。 WindowsStandard 模式的行为相同,只是在 Windows 模式下,以下文件的调用会自动使用 Legacy 风格参数传递。

      cmd.exe
      cscript.exe
      wscript.exe
    • .bat结尾
    • .cmd结尾
    • .js结尾
    • .vbs 结尾
    • .wsf 结尾
    • 如果 $PSNativeCommandArgumentPassing 设置为 LegacyStandard,则解析器不会检查这些文件。

      笔记

      以下示例使用 TestExe.exe 工具。您可以从源代码构建TestExe。请参阅 PowerShell 源存储库中的 TestExe。

      此更改带来的新行为:

      • 带有嵌入引号的文字或可扩展字符串现在保留引号:

        PS> $a = 'a" "b'
        PS> TestExe -echoargs $a 'c" "d' e" "f
        Arg 0 is <a" "b>
        Arg 1 is <c" "d>
        Arg 2 is <e f>
        
      • 现在保留作为参数的空字符串:

        PS> TestExe -echoargs '' a b ''
        Arg 0 is <>
        Arg 1 is <a>
        Arg 2 is <b>
        Arg 3 is <>
        

      这些示例的目标是将目录路径(带有空格和引号)"C:\Program Files (x86)\Microsoft\" 传递给本机命令,以便它接收作为带引号的路径细绳。

      WindowsStandard 模式下,以下示例产生预期结果:

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

      要在 Legacy 模式下获得相同的结果,您必须转义引号或使用停止解析标记 (--%):

      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 --% """%ProgramFiles(x86)%\Microsoft\""
      

      笔记

      PowerShell 不会将反斜杠 (\) 字符识别为转义字符。它是 ProcessStartInfo.ArgumentList 的底层 API 使用的转义字符。

      PowerShell 7.3 还添加了跟踪本机命令参数绑定的功能。有关详细信息,请参阅跟踪命令。

      将参数传递给 PowerShell 命令

      从 PowerShell 3.0 开始,您可以使用参数结束标记 (--) 来阻止 PowerShell 将输入解释为 PowerShell 参数。这是 POSIX Shell 和实用程序规范中指定的约定。

      参数结束标记

      参数结束标记 (--) 指示其后面的所有参数都将以实际形式传递,就像在它们周围放置双引号一样。例如,使用 -- 您可以输出字符串 -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>
      

      波形符 (~)

      波形符 (~) 在 PowerShell 中具有特殊含义。当它在路径开头与 PowerShell 命令一起使用时,波浪号字符将扩展到用户的主目录。如果波浪号字符在路径中的其他任何位置使用,它将被视为文字字符。

      PS D:\temp> $PWD
      
      Path
      ----
      D:\temp
      
      PS D:\temp> Set-Location ~
      PS C:\Users\user2> $PWD
      
      Path
      ----
      C:\Users\user2
      

      在此示例中,New-ItemName 参数需要一个字符串。波形符字符被视为文字字符。要更改到新创建的目录,您必须使用波浪号字符限定路径。

      PS D:\temp> Set-Location ~
      PS C:\Users\user2> New-Item -Type Directory -Name ~
      
          Directory: C:\Users\user2
      
      Mode                 LastWriteTime         Length Name
      ----                 -------------         ------ ----
      d----            5/6/2024  2:08 PM                ~
      
      PS C:\Users\user2> Set-Location ~
      PS C:\Users\user2> Set-Location .\~
      PS C:\Users\user2\~> $PWD
      
      Path
      ----
      C:\Users\user2\~
      

      当您在本机命令中使用波浪号字符时,PowerShell 会将波浪号作为文字字符传递。在路径中使用波浪号会导致 Windows 上不支持波浪号字符的本机命令出现错误。

      PS D:\temp> $PWD
      
      Path
      ----
      D:\temp
      
      PS D:\temp> Get-Item ~\repocache.clixml
      
          Directory: C:\Users\user2
      
      Mode                 LastWriteTime         Length Name
      ----                 -------------         ------ ----
      -a---           4/29/2024  3:42 PM          88177 repocache.clixml
      
      PS D:\temp> more.com ~\repocache.clixml
      Cannot access file D:\temp\~\repocache.clixml
      

      参见

      • about_Command_Syntax

      您需要 登录账户 后才能发表评论

      取消回复欢迎 发表评论:

      关灯