如何在命令行上传递一系列值 - 将表达式作为参数传递

时间:2016-12-21 02:41:15

标签: powershell parsing command-line syntax parameter-passing

我有以下代码:

$srv_range = 29..30+40+50..52
$srv_range.GetType()
$NewVMTemplate = New-Object psobject
$NewVMTemplate | Add-Member -MemberType NoteProperty -Name Name -Value $null

$srv_range | % {
    $pod= $_
    $servers = @()
    1..2 | % {
        $server = $NewVMTemplate | Select-Object *
        $server.Name = "pod" + "{0:D2}" -f $pod + "-srv" + $_
        $servers += $server
    }
    ForEach ( $server in $servers) {
        write-host $server.Name
    }
} 

输出:

PowerCLI C:\ .\eraseme.ps1

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array
pod29-srv1
pod29-srv2
pod30-srv1
pod30-srv2
pod40-srv1
pod40-srv2
pod50-srv1
pod50-srv2
pod51-srv1
pod51-srv2
pod52-srv1
pod52-srv2

我想从CLI输入范围,但是我使用此代码获得以下输出

param(

    [Parameter(Mandatory=$False)] $srv_range

)
#$srv_range = 29..30+40+50..52
$srv_range.GetType()
$NewVMTemplate = New-Object psobject
$NewVMTemplate | Add-Member -MemberType NoteProperty -Name Name -Value $null

$srv_range | % {
    $pod= $_
    $servers = @()
    1..2 | % {
        $server = $NewVMTemplate | Select-Object *
        $server.Name = "pod" + "{0:D2}" -f $pod + "-srv" + $_
        $servers += $server
    }
    ForEach ( $server in $servers) {
        write-host $server.Name
    }
} 

PowerCLI C:\ .\eraseme.ps1 29..30+40+50..52

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     String                                   System.Object
pod29..30+40+50..52-srv1
pod29..30+40+50..52-srv2

如何从CLI输入范围并获得与第一个代码相同的结果?

1 个答案:

答案 0 :(得分:11)

您的问题是论坛 29..30+40+50..52.\eraseme.ps1 29..30+40+50..52来电中被视为字符串文字 - 表达

强制识别为表达式,只需将参数括在(...) 中:

.\eraseme.ps1 (29..30+40+50..52)

请注意,您可以通过使用更具体的类型声明参数来使脚本更加健壮,在这种情况下,尝试使用字符串调用它会立即失败:

 [Parameter(Mandatory=$False)] [int[]] $srv_range

(其他优化也可以应用于您的脚本。)

可选背景信息

至于何时将未加引号的标记视为表达式参数中的(可扩展)字符串模式 (参见about_Parsing):

  • (...)$(...)@(...) 自己在令牌的开头创建新的解析上下文 ,其中可以使用表达式甚至嵌套命令

    • (...)足以支持单个表达式或命令。 $(...)子表达式运算符)可以包含多个表达式/命令;所以可以@()数组子表达式运算符),并且它还确保其输出始终被视为数组

    • 值得注意的是,以下表达式 未被包含在以上某个内容中

      • [...](输入文字)并访问其成员,例如[Environment]::Version
      • ..(范围表达式),例如1..10
    • 如果在令牌的开头(...)$(...)@(...)后面跟着其他字符,则第一个附加字符被视为新的单独参数的开始

    • 相比之下,如果他们 类似于$(...)内部(可扩展字符串),"..."启动一个新参数,它是一个表达式,(...)被视为文字@(...) @再次启动一个表达式的新参数。
  • (...)后跟变量的名称(例如,@),其中包含参数值的集合或哈希表,启动parameter splatting

  • @params可用于传递哈希表文字(例如@{ ... })。

  • @{ key = 'value' }创建一个脚本块({ ... })。

  • 自己在令牌开头,变量引用,包括成员访问(属性访问,方法调用,索引)可以按原样使用

    • [scriptblock]$HOME$PSVersionTable.PSVersion$someArray[0] 等表达式被识别,并作为其固有类型返回。

    • 没有成员访问权限,即使用简单的变量引用(例如$someString.ToUpper()),后续字符(可能)被视为相同的一部分然后将该参数解释为可扩展字符串 - 请参阅下文。

    • 使用成员访问权限,任何其他字符中的第一个被视为新参数的开头(例如,$HOME会导致两个参数:$foo.Length-more和字符串文字$foo.Length)的值。

  • 其他所有内容都被视为可扩展字符串 ,即类似到双引号字符串的内容,< em>除 元字符 [1] 仍然需要转义某些令牌被解释为多个参数

    • 可扩展表示嵌入式简单变量引用(例如,-more$HOME\Desktop)插值(用其字符串值替换)。
      请注意,这可能会导致表示与控制台中显示的给定值的默认输出格式不同(例如,有关详细信息,请参阅this answer)。

      • $env:APPDATA\Test中附加变量名称,以便在必要时将其与后续字符消除歧义(例如{...})。
    • 访问变量值属性或使用索引或调用方法或嵌入任意命令,您必须将表达式括在${HOME} 中,例如$(...)

    • 通常,最安全的是在v$($PSVersionTable.PSVersion) 中包含嵌入了变量引用/表达式的标记,因为它避免了以下边缘情况:

      • "..." start 的未加引号的标记被解释为可扩展字符串的一部分,它被视为一个单独的参数(例如,$(...)会产生两个参数:Write-Output $('ab')c和文字$('ab')的结果。)
      • c在令牌 start 后紧跟一个简单的变量引用或子表达式会导致单独的参数
        (例如,.会产生两个参数:文字.$HOME,以及.的值<)
    • 注意:即使扩展的结果是一个字符串,它也不一定保持一个:最终类型由其类型决定参数是扩展值绑定的手头命令。

    • 转义/引用

      • PowerShell比$HOME有更多元字符,值得注意的陷阱是cmd.exe必须被转义才能被视为文字,因为{{1}是PowerShell的数组构造运算符。

      • 转义单个字符,请在其前面添加 ,(反引号)

        < / LI>
      • 避免需要单独转发元字符 ,请将值括在 ,(双引号) `(单引号)

        • 如果您希望字符串插入(扩展),请使用双引号,即,如果您希望能够嵌入变量引用和子表达式。

          • Inside 双引号字符串"..." - 转义以下字符。将它们视为文字:'...'
        • 使用单引号将值视为文字

          • 内部单引号字符串,将`转义为` " $
      • 单引号或双引号通常是在值中转义空格的最简单方法。

  • 最后,请注意 ' ,即所谓的停止解析符号(PSv3 +),完全改变了所有剩余参数的解释:设计用于遗留''命令行,停止解释除--% - 样式cmd.exe环境变量的扩展之外的其余部分。请参阅Get-Help about_Parsing

至于使用引用的代币:

  • cmd.exe%...% 自己在令牌的开头

    • 这些通常被解析:作为文字('...')或可扩展("...")字符串。
    • 任何其他字符都会导致第一个附加字符被视为新的单独参数的开头。
  • '...'"..."

    • 对它们进行常规评估,并将结果(即删除了引号)附加到它们之前的内容(评估为)。

[1] 参数模式元字符(具有特殊句法含义的字符)是:
'...'
其中,"..."仅适用于令牌的 start

<强>实施例

<space> ' " ` , ; ( ) { } | & < > @ #