具有类型赋值的添加成员怪异 [英] add-member weirdness with type assignment

查看:24
本文介绍了具有类型赋值的添加成员怪异的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在下面的代码中,为什么name1的[int]类型赋值被忽略,而实际上被视为值的一部分?错误?

$name1 = 4
$name2 = 4
$name3 = 4

$myObject = New-Object System.Object
$myObject | Add-Member -type NoteProperty -name name1 -Value [int]$name1
$myObject | Add-Member -type NoteProperty -name name2 -Value $($name2 -as [int])
$myObject | Add-Member -type NoteProperty -name name3 -Value $([int]$name3)

$myObject

输出:

name1  name2 name3
-----  ----- -----
[int]4     4     4

Powershell版本:

get-host | select-object version

Version       
-------       
5.1.19041.1023

推荐答案

现有答案中有很好的信息,但让我尝试系统地概述一下:

tl;dr

为了表达式(例如[int] $name1)、或(嵌套)命令(例如Get-Date -Format yyyy)作为参数传递给命令(例如Add-Member),将其括在(...)Add-Member -type NoteProperty -name name1 -Value ([int] $name1)

相反,$(...)在此方案中通常不需要subexpression operator,使用它可能会产生副作用-请参阅this answer

  • 简而言之:(在expandable strings"..."之外),您只需要$(...)语言语句括起来(如if语句或foreach循环)或多个语句(命令、表达式和语言语句的任意组合,用;分隔)。

PowerShell的解析模式:

PowerShell有两种基本解析模式

  • 参数模式,其工作方式与类似shell

    • 在参数模式下,第一个内标识被解释为命令名(cmdlet、函数、别名或外部可执行文件或.ps1脚本的路径名称),后跟以空格分隔的参数列表,其中字符串可以是不带引号的[1]
  • 表达式模式,类似编程语言,字符串必须用引号括起来,可以使用赋值、foreachwhile循环等运算符和语言语句,强制转换

概念性about_Parsing介绍这些模式;简而言之,它是给定上下文中的第一个内标识,它决定应用哪种模式。

给定的语句可能由在任一模式下解析的部分组成,这确实是上面发生的情况:

  • 因为您的语句以命令名(Add-Member)开头,所以它以参数模式进行分析。

  • (...)强制新的解析上下文,在当前情况下([int] $name1)以表达式模式解析,因为以[开头)。

被认为是元字符(具有特殊语法意义的字符)在不同的分析模式中不同:

  • [=仅在表达式模式中特殊,而在参数模式中不特殊,在该模式下,它们将逐字使用。

  • 相反,标记-initial@后跟变量name仅在参数模式下特殊,在该模式下它用于参数splatting

复合参数[int]$name1因此被视为可扩展字符串,并导致逐字字符串[int]4

某些表达式用作命令参数(假设$var = 'Foo')时,不需要括在(...)中:

  • A独立变量引用(例如Write-Output $varWrite-Output $env:OS)
  • 对此类引用的属性访问(例如Write-Output $var.Length)
  • 方法调用此类引用(例如Write-Output $var.ToUpper())

请注意,这些参数与其原始数据类型一起传递,而不是字符串(尽管字符串可以由接收命令执行)。

陷阱

  • 有时需要显式使用"..."以取消属性访问解释,并逐字解释变量引用后面的.(例如Write-Output "$var.txt"以便逐字解释foo.txt)。

  • 如果将$(...)用作复合参数的一部分,而不使用显式"..."引号,则如果$(...)子表达式开始该参数(例如,Write-Output $('a' + 'b')/c传递两个参数,即逐字ab/c),则该参数将被拆分为多个参数(例如,Write-Output $('a' + 'b')/c传递两个参数,即逐字ab/c

  • 同样,仅当参数以不带引号的标记开头(例如,Write-Output One"$var"'$Two'按预期工作并逐字生成OneFoo$Two,但Write-Output 'One'"$var"'$Two'作为三个参数、逐字OneFoo$Two)开始时,混合使用带引号和不带引号的字符串以形成单个参数才有效。

简而言之:

  • 参数解析的确切规则很复杂:

    • This answer汇总了无引号参数的规则。
    • This answer汇总了在单个参数中混合使用带引号和不带引号的字符串
    • This answer)(下部)概述了PowerShell的字符串文字。
  • 为安全起见,避免在"..."外部使用$(...),并避免在单个字符串参数中混合引用样式;在表达式中使用(单)"..."字符串(例如Write-Output "$(Split-Path $PROFILE)/foo.txt"或)或字符串连接(Write-Output ('One' + $var + '$Two')


[1]假设它们既不包含空格,也不包含PowerShell的任何元字符(请参见this answer)。虽然引号通常采用根据需要将整个参数括在单引号或双引号中(例如'foo bar'"foo $var")的形式,但也可以使用反号(`)引出(转义)单个字符(例如foo` bar),这是PowerShell的转义字符。

这篇关于具有类型赋值的添加成员怪异的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆