为什么我的脚本块在执行时被视为字符串,而不是作为脚本执行?

时间:2018-08-21 15:49:03

标签: powershell

我希望以下脚本块能够执行并返回类型byteint的数字,但是引号内的所有内容都只是字符串而不是脚本。

$a=(&{Param($t);"[$t]`$num=10;`$num+=2;`$num"} byte)
$a
# OUTPUTS STRING [byte]$num=10;$num+=2;$num
# NOT NUMBER 12

$ty="int"
$b=(&{"[$ty]`$num=5;`$num+=2;`$num"})
$b
# OUTPUTS STRING [int]$num=5;$num+=2;$num
# NOT NUMBER 7

我如何使其按预期工作? 谢谢

2 个答案:

答案 0 :(得分:2)

当用引号引起来时(请参见about_quoting_rules),您正在创建一个字符串:

"[$t]`$num=10;`$num+=2;`$num"

因为这就是您要组装的东西,也就是要返回的东西。


我假设您正在尝试转换为特定类型(整数/字节):

[$t]`$num=10

您可以改用LanguagePrimitives.ConvertTo方法,因为它将为您完成此操作:

[System.Management.Automation.LanguagePrimitives]::ConvertTo(Object, Type)

我先定义脚本块,然后分别调用它:

$a={ codehere }
& $a param1 param2

随身携带所有东西:

$a={Param($t,$num);$num=[System.Management.Automation.LanguagePrimitives]::ConvertTo($num, $t);$num+2}
& $a byte 5

答案 1 :(得分:2)

补充James C.'s helpful answer,它很好地解释了问题,并包含一个有局限性的解决方案 [1] 替代解决方案

隔离使用的脚本块确实就像匿名函数一样(它们也是脚本和命名函数的基础)。

虽然无法使用非文字类型名称进行广播 /类型约束,但是您可以使用-as个具有类似效果的运算符

PS> & { param($t) $num = 10; $num+=2; $num -as $t } byte # !! use -as $t on OUTPUT
12  # type is [byte]

注意事项

  • 与PowerShell强制转换不同,-as运算符是文化敏感的-对于某些类型,但对于其他类型则不是:例如,它对[datetime]是文化敏感的,但不适用于[double]

  • 如果无法进行转换,则-as会悄悄返回$null,因此您可能必须明确处理这种情况。

  • 由于-as不能用于类型约束变量,因此后续操作可以更改值的数据类型。

    • 如果您在$num = 10 -as [byte]之后加上$num += 2,确实会发生这种情况:加法会将类型隐式更改为[int]
    • 因此,将-as运算符应用于输出,或在必要时应用于每个中间操作。
      • 提防诸如+=之类的复合运算符,其中-as不能按预期运行;例如,使用$num += 2 -as [byte]代替$num = ($num + 2) -as [byte]
  • 顺便说一句:如果 New-Variable支持类型约束,则可以按照New-Variable -Type $t -Name num -Value 10的方式进行选择;当前(自Windows PowerShell v5.1 / PowerShell Core 6.1.0起)没有,但是may in the future


或者,用[scriptblock]::Create() 从字符串表示形式创建脚本块 ,该脚本块允许您将类型名称“烘焙”到字符串中:

PS> & ([scriptblock]::Create('[{0}] $num=10; $num+=2; $num' -f 'byte'))
12  # type is [byte]

注意事项

  • 仅在可以完全控制或信任其内容的字符串上使用此技术,因为可以用这种方式构造任意命令。

  • 此外,出于可维护性考虑,此技术仅适用于小段代码。


[1] [System.Management.Automation.LanguagePrimitives]::ConvertTo()并不完全等同于强制转换,因为它没有涵盖"dynamic objects that provide their own conversions."