为什么Powershell默默地将带有一项的字符串数组转换为字符串


33

考虑以下Powershell脚本,该脚本在C:\中搜索名称为“ og”的文件夹:

PS C:\>(ls |%{$ _。Name} |?{$ _。Contains(“ og”)})
性能日志
程序文件
setup.log

现在,我缩小搜索范围以仅获取一项:

PS C:\>(ls |%{$ _。Name} |?{$ _。Contains(“ Prog”)})
程序文件

奇怪的是,第一个操作产生一个数组,而第二个操作(IMHO在语义上是相同的操作,因此它应产生相同类型的结果)产生一个字符串。在以下结果中可以看出:

PS C:\>(ls |%{$ _。Name} |?{$ _。Contains(“ og”)}))。长度
3
PS C:\>(ls |%{$ _。Name} |?{$ _。Contains(“ Prog”)}))。长度
13

这可能非常令人讨厌,因为与“ og”匹配的文件夹显然比与“ prog”匹配的文件夹少。

显然,PowerShell隐式地将单个项目数组“拆箱”到单个对象,并且我们永远都不会得到长度为1的数组。似乎每次我想对通过管道传递的结果进行计数时,我都必须检查是否m是否处理数组。

如何防止这种情况发生?您如何处理?


这些从StackOverflow上可能会有帮助:stackoverflow.com/questions/1827862/... stackoverflow.com/questions/1390782/...如果你没有对管道$_.Contains,然后%{,,$_.Name}工作... ...
鲍勃

Answers:


56

显然,PowerShell将单个项目数组隐式“解包”到单个对象,

零个结果$null

如何防止这种情况发生?

你不能

您如何处理?

使用数组构造函数(@(...))强制集合(可能包含零个或一个元素)返回:

$res = @(ls | %{$_.Name} | ?{$_.Contains("Prog")})

谢谢,这太完美了!我有15个声誉会立即投票。
cheesus SO停止伤害Monica

2
不确定您可以“强制”使用它。@(1) | ConvertTo-Json仍返回1而不是[1]
马克

@Marc:ConvertTo-Json从不返回集合:它读取整个输入并将其转换为单个字符串。如果要分别转换输入对象,则需要分别处理每个对象。
理查德

1
@Richard,我想您会误会:我和其他许多人基本上都希望将整个对象(即集合)序列化(例如用于外部持久性)。我们不希望分别处理集合中的每个对象。ConvertTo-Json应该返回一个字符串,如果运行通过,则ConvertFrom-Json会返回原始对象,尽管它是一个空数组/集合。
Marc

@Marc这个问题的重点是避免将单个元素数组视为该元素(由于随后的PSH更改而引起的问题较小:请注意问题的日期)。您正在谈论完全不同的情况(将集合强制为单个对象),因此引起我的误解。
理查德

2

在PowerShell v3中已解决此问题:

http://blogs.microsoft.co.il/blogs/scriptfanatic/archive/2012/03/19/Counting-objects-in-PowerShell-3.0.aspx

附带说明,您可以使用通配符查找名称是否包含某些内容:

PS> ls *og*

6
Shay,我还不能对答案发表评论,但您的说法不正确。PowerShell仍然将元素装箱,但正如您所指出的,它们具有给单个项目“ Count”值。不过,单项结果仍未装箱。您可以针对PS 3测试上述示例,然后查看结果。
Tohuw

1
PS 5中的行为仍然相同
。– MEMark

是的,防御仍然存在
James Wiseman

1
这种行为仍然是PS 6.0.1相同
spuder

2

请注意这两个结果之间的区别:

PS C:\> ConvertTo-Json -InputObject @(1)
[
    1
]
PS C:\> @(1)|ConvertTo-Json
1
PS C:\>

关键是通过管道操作完成“拆箱”。如果我们使用InputObject而不是管道,则ConvertTo-Json仍将对象视为数组。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.