Select-Object -Unique returns 字符串而不是字符串数组

Select-Object -Unique returns String instead of String array

这种情况只出现在长度为1的数组中。

示例:

$array = @("55") 
$arrayAfterUnique = $array | Select-Object -Unique 

所以我希望 $arrayAfterUnique 是一个长度为 1 的数组。
但是,Select-Object 会从中生成一个字符串。

这个问题有简单的解决方法吗?

您可以添加自定义函数以转换为数组 as shown here

function ToArray
{
  begin
  {
    $output = @()
  }
  process
  {
    $output += $_
  }
  end
  {
    return ,$output
  }
}

用法:

$array = @("55") 
$arrayAfterUnique = $array | Select-Object -Unique | ToArray
$arrayAfterUnique.GetType() # Returns System.Array

更新:

值得一提的是,由于使用 +-,此方法可能会降低性能,因为会为每个项目创建一个新数组。

However Select-Object will make a string out of it

不完全 - Select-Object 将 return 0 个或更多 个对象 ,并且根据数量,PowerShell 运行时将决定结果是否为存储为标量或数组。

无论输出中有多少对象,您都可以强制结果为数组,方法是使用数组子表达式运算符 @():

$array = @("55") 
$arrayAfterUnique = @($array | Select-Object -Unique)

补充,很好的说明了问题:

@(...) 的替代方法是 type-constrain 结果变量 [array] 放置到left的变量,为了保证采集到的结果总是一个数组:

# Ensure that $arrayAfterUnique always contains an array.
[array] $arrayAfterUnique = 1, 1 | Select-Object -Unique 

[array] 实际上与 [object[]] 相同,即常规 PowerShell 数组。

如果 RHS 命令的输出是单个值(标量),该值现在会自动转换为单元素数组;对于多个输出值,PowerShell 隐式创建的用于收集输出的 [object[]] 数组按原样存储。

注意:对变量进行类型约束意味着将来的赋值也必须是锁定类型或可转换为它;例如,稍后执行 $arrayAfterUnique = 42 再次将整数 42 转换为单元素数组。

但是,通常没有必要区分标量和数组,因为 PowerShell 允许您处理标量 数组,给它们一个 .Count 属性 和值 1 并允许 索引 [0][-1] - 请参阅 了解更多信息。


至于输入方:

在将数组发送到管道时,PowerShell 枚举它们 - 即元素被一个接一个发送到下一个流水线段中的命令。

因此,单值输入实际上与单元素数组输入相同。

也就是说,以下两个命令的行为相同:

# In both cases, Select-Object receives single value '55'
  '55'  | Select-Object -Unique   # single value
@('55') | Select-Object -Unique   # single-element array

如果需要保证一个数组作为一个整体发送到管道,在它前面加上, (数组构造运算符)[1]:

# Send array 1, 2 as a whole to ForEach-Object
# Note the need for (...) to clarify precedence.
, (1, 2) | ForEach-Object { $_.GetType().Name } # -> 'Object[]'

# Less efficient, but conceptually clearer alternative:
Write-Output -NoEnumerate 1, 2

[1] 这将数组包装在一个辅助的单元素辅助数组中,PowerShell 枚举的正是该辅助数组,因此发送它的一个也是唯一的元素——原始数组——作为-正在通过管道。