powershell - 在PowerShell中 “$myvariable =”和Set-Variable有什么区别?

标签 powershell

在研究PowerShell脚本语言时,我尝试使用“写输出”命令来显示变量。

我使用另一种方法来创建变量。

例:
$myvariable = 0x5555Set-Variable -Name myvariable2 -Value 0x5555
这两个变量的数据类型为Int32。

当我使用以下命令时,
Write-Output $myvariable $myvariable2
结果是218450x5555

这两个变量之间有什么区别?

如何显示格式结果,例如printf %d %x

最佳答案

PetSerAl像以前一样多次在评论中给出了关键的指针(后来帮助改进了这个答案):

从PowerShell Core 6.2.0起编写。

PowerShell会将看起来像数字的无引号的文字参数解析为数字,并将其包装在“半透明”的[psobject]实例中,其目的还在于保留指定为字符串的确切参数。

半透明的意思是生成的$myVariable2:

  • 主要是一个数字-一个常规的(未包装的)[int]实例-用于计算;例如,$myVariable2 + 1正确返回21846
  • 另外,当您使用.GetType()或通过Get-Member cmdlet询问其类型时,它显示该数字。换句话说:在这种情况下,PowerShell假装没有包装器(有关变通方法,请参见下文)。
  • 在情况上的行为类似于字符串-在以下情况下返回与指定内容完全相同的原始参数文字:

    直接在控制台上打印时,以及通常使用Out-* cmdlet(例如Out-File(但不是Set-Content)和Format-* cmdlet)时,
  • 输出格式。
  • 使用 -f , PowerShell's format operator格式化
  • 字符串(基于.NET的 String.Format() method;例如'The answer is {0}' -f 42等效于[string]::Format('The answer is {0}', 42))。
  • 令人惊讶的是,它的行为不像可扩展字符串("$myVariable2")中的字符串,当您调用.ToString()方法($myVariable2.ToString())和Set-Content(因此也)时,它的行为不一样。

  • 请注意,将数字文字指定为命令参数本质上是模棱两可的,因为即使字符串参数通常也不需要引号(除非它们包含特殊字符),例如,诸如1.0之类的参数可以解释为版本字符串。或作为浮点数。

    PowerShell解决歧义的方法是将此类 token 解析为数字,但是如上所示,在某些情况下,它充当字符串[1]。

    通过键入参数以指示绑定(bind)到它的参数是字符串还是数字,可以完全避免歧义。

    但是,-ValueSet-Variable cmdlet的New-Variable参数是-必不可少的[object]类型,因为它必须能够接受任何类型的值,并且这些cmdlet没有可让您指示所需数据类型的参数。

    解决方案是通过将其括在-Value 中,强制将(...)参数视为表达式的结果而不是未引用的文字参数:
    # Due to enclosing in (...), the value that is stored in $myvariable2 
    # is *not* wrapped in [psobject] and therefore behaves the same as
    # $myvariable = 0x55555
    Set-Variable -Name myvariable2 -Value (0x5555)
    

    相反,如果不应用上述解决方案,则有两种选择来解开$myvariable2的按需值(value):
    # OK: $myvariable isn't wrapped in [psobject], so formatting it as a
    #     hex. number works as expected:
    PS> 'hex: 0x{0:x}' -f $myvariable
    hex: 0x5555  # OK: Literal '0x' followed by hex. representation of the [int]
    
    # !! Does NOT work as expected, because $myvariable2 is treated as a *string*
    # !! That is, {0:x} is effectively treated as just {0}, and the string
    # !! representation stored in the [psobject] wrapper is used as-is.   
    PS> 'hex: 0x{0:x}' -f $myvariable2
    hex: 0x0x5555  # !! Note the extra '0x'
    
    # Workaround 1: Use a *cast* (with the same type) to force creation of
    #               a new, *unwrapped* [int] instance:
    PS> 'hex: 0x{0:x}' -f [int] $myvariable2
    hex: 0x5555  # OK
    
    # Workaround 2: Access the *wrapped* object via .psobject.BaseObject.
    #               The result is an [int] that behaves as expected.
    PS> 'hex: 0x{0:x}' -f $myvariable2.psobject.BaseObject
    hex: 0x5555  # OK
    

    检测到[psobject]包装的值:

    最简单的解决方案是使用-is [psobject]:
    PS> $myvariable -is [psobject]
    False  # NO wrapper object
    
    PS> $myvariable2 -is [psobject]
    True  # !! wrapper object
    

    (PetSerAl提供了以下不太明显的替代方法:[Type]::GetTypeArray((, $myvariable2)),它绕过了PowerShell的“包装包裹”技巧。)

    [1] 将输入字符串表示形式保留为作为命令参数传递的隐式数字:

    与传统的shell不同,PowerShell使用丰富的类型,因此诸如01.2之类的参数文字会立即解析为数字-在这种情况下为[double],如果按原样使用,则会在输出上产生不同的表示形式,因为-一次解析为数字-默认输出格式应用于输出(其中数字必须再次转换为字符串):
     PS> 01.2
     1.2  # !! representation differs (and is culture-sensitive)
    

    但是,目标命令的意图最终可能会将参数视为字符串,在这种情况下,您不希望更改输出表示形式。
    (请注意,虽然您可以使用引号(01.2'01.2')从字符串中消除数字的歧义,但命令参数通常不需要这样做,这与传统Shell中不需要的方式相同。)

    出于这个原因,使用[psobject]包装器来捕获原始字符串表示形式并将其用于输出。

    注意:可以说,一种更一致的方法是始终将未加引号的文字参数视为字符串,除非在PowerShell命令中绑定(bind)了显式数字类型的参数。

    这是调用外部程序的必要条件,参数只能以字符串形式传递给外部程序。

    也就是说,在将初始解析为数字之后,PowerShell在构建命令行(Windows)或将参数(作为类Unix平台)传递作为外部程序调用的一部分时,必须使用原始的字符串表示形式。

    如果不这样做,则可能会无意中更改参数,如上所示(在上面的示例中,外部程序将接收字符串1.2而不是最初传递的01.2)。

    您还可以使用带有无类型参数的PowerShell代码来演示此行为-尽管请注意,通常最好使用显式键入参数:
     PS> & { param($foo) $foo.GetType().Name; $foo } -foo 01.2
     Double  # parsed as number - a [double]
     01.2    # !! original string representation, because $foo wasn't typed
    
  • $foo是一个无类型的参数,这意味着将使用PowerShell在初始解析文字01.2时推断出的类型。
  • 但是,鉴于命令(在这种情况下为脚本块({ ... }))没有声明$foo的参数类型,隐式使用的[psobject]包装器在输出中显示了原始字符串表示形式。
  • 关于powershell - 在PowerShell中 “$myvariable =”和Set-Variable有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55194805/

    相关文章:

    windows - 将 PowerShell 用于 Visual Studio 命令提示符

    powershell - 在powershell中替换时正则表达式无效

    powershell - 有没有办法在 PowerShell 中的许多函数调用中为命名参数设置默认值?

    powershell - 数组中奇怪的不存在的属性

    powershell - 通过TestComplete通过Vsphere自动化管理(升级/新)VMWare的过程

    Powershell 哈希表未按预期写入文件 - 仅接收 "System.Collections"行

    powershell - Convertfrom-string 删除前导零

    Powershell - 将本地时间转换为不同的时区

    windows - 在 Windows Power shell 脚本中编写 tsv 文件的优化方法是什么?

    命令行界面还是 PowerShell?