问题 - 通用描述
从about_pipelines(help pipeline
)的帮助中可以看出,powershell在流水线下发送一个对象¹。因此,Get-Process -Name notepad | Stop-Process
会在管道下发送一个进程。
假设我们有第三方CmdLet(Do-SomeStuff)无法以任何方式修改或更改。 Do-SomeStuff在传递一个字符串数组或传递一个字符串对象时执行不同。
Do-SomeStuff只是一个示例,它可以替代ForEach-Object
,Select-Object
,Write-Host
(或任何其他CmdLet接受管道输入) < / p>
Do-SomeStuff将在此示例中处理数组中的各个项目。
$theArray = @("A", "B", "C")
$theArray | Do-SomeStuff
如果我们想将完整数组作为一个对象发送到Do-SomeStuff,可以尝试这样的事情
@($theArray) | Do-SomeStuff
但是由于PowerShell“忽略”了新的单项数组,因此它不会产生预期的结果。
那么,你如何“强迫”$theArray
作为单个数组对象传递给管道而不是当时的内容项?
问题 - 实际例子
如下所示,Write-Host
的输出在传递数组时是不同的,或者如果它一次传递一个数组中的单个项目。
PS C:\> $theArray = @("A", "B", "C")
PS C:\> Write-Host $theArray
A B C
PS C:\> $theArray | foreach{Write-Host $_}
A
B
C
PS C:\> @($theArray) | foreach{Write-Host $_}
A
B
C
如何让$theArray | foreach{Write-Host $_}
生成与Write-Host $theArray
相同的输出?
脚注
正常的字符串数组
PS C:\> @("A", "B", "C").GetType().FullName
System.Object[]
传递给Foreach-Object的正常字符串数组
PS C:\> @("A", "B", "C") | foreach{$_.GetType().FullName}
System.String
System.String
System.String
数组中的每个字符串由ForEach-Object CmdLet一次处理一次。
一组数组,其中“内部”数组是字符串数组。
PS C:\> @(@("A", "B", "C"), @("D", "E", "F"), @("G", "H", "I")) | foreach{$_.GetType().FullName}
System.Object[]
System.Object[]
System.Object[]
数组中的每个数组都由ForEach-Object CmdLet一次处理,并且输入中每个子数组的内容作为一个对象处理,即使它是一个数组。
答案 0 :(得分:28)
简答:使用一元数组运算符.leftMenu,
.rightMenu,
.centerMenu {
text-align: center;
display: inline-block;
border-bottom: solid .1em;
display: -webkit-flex;
}
.leftMenu,
.rightMenu {
background-color: #454ed6;
height: 2em;
padding-top: 1em;
width: 17.5%;
-webkit-justify-content: space-around;
}
.leftMenu {
float: left;
}
.rightMenu {
float: right;
}
.centerMenu a {
display: block;
height: 2em;
}
.centerMenu {
width: 65%;
height: 6em;
background-color: #86acbe;
-webkit-flex-direction: column;
-webkit-justify-content: space-around;
}
:
,
答案很长:关于,$theArray | foreach{Write-Host $_}
运算符,您应该了解一件事:它始终将其内容解释为语句,即使内容只是表达式。请考虑以下代码:
@()
我在这里添加了显式结束语句标记$a='A','B','C'
$b=@($a;)
$c=@($b;)
,尽管PowerShell允许省略它。 ;
是三个元素的数组。 $a
陈述的结果是什么? $a;
是一个集合,因此应该枚举集合,并且每个单独的项都应该通过管道传递。因此$a
语句的结果是写入管道的三个元素。 $a;
看到三个元素,但不是原始数组,并从中创建数组,因此@($a;)
是三个元素的数组。同样的方式$b
是相同三个元素的数组。因此,当您编写$c
创建数组时,会复制@($collection)
的元素,而不是单个元素的数组。
答案 1 :(得分:4)
逗号字符使数据成为数组。为了使管线将数组作为数组处理,而不是单独对每个数组元素进行操作,您可能还需要用括号包装数据。
如果您需要评估数组中多个项目的状态,这非常有用。
使用以下功能
function funTest {
param (
[parameter(Position=1, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
[alias ("Target")]
[array]$Targets
) # end param
begin {}
process {
$RandomSeed = $( 1..1000 | Get-Random )
foreach ($Target in $Targets) {
Write-Host "$RandomSeed - $Target"
} # next target
} # end process
end {}
} # end function
请考虑以下示例:
将数组括在括号中并不能保证函数将在一个进程调用中处理值数组。在这个例子中,我们看到了数组中每个元素的随机数变化。
PS C:\> @(1,2,3,4,5) | funTest
153 - 1
87 - 2
96 - 3
96 - 4
986 - 5
只需添加前导逗号,也不保证函数将在一个进程调用中处理值数组。在这个例子中,我们看到了数组中每个元素的随机数变化。
PS C:\> , 1,2,3,4,5 | funTest
1000 - 1
84 - 2
813 - 3
156 - 4
928 - 5
使用括号中的前导逗号和值数组,我们可以看到随机数保持不变,因为正在利用函数的foreach命令。
PS C:\> , @( 1,2,3,4,5) | funTest
883 - 1
883 - 2
883 - 3
883 - 4
883 - 5
答案 2 :(得分:2)
如果你不介意你的过程是一个功能,那么这是一个老派的解决方案。
示例:您希望将数组复制到剪贴板的方式允许您在没有任何PSRemoting连接的情况下在另一个系统上再次构建它。所以你想要一个包含&#34; A&#34;,&#34; B&#34;和&#34; C&#34;转换为字符串: @(&#34; A&#34;&#34; B&#34;&#34; C&#34) ...而不是文字数组。
所以你建立了这个(由于其他原因这不是最优的,但留在主题上):
# Serialize-List
param
(
[Parameter(Mandatory, ValueFromPipeline)]
[string[]]$list
)
$output = "@(";
foreach ($element in $list)
{
$output += "`"$element`","
}
$output = $output.Substring(0, $output.Length - 1)
$output += ")"
$output
,当您将数组直接指定为参数时,它可以正常工作:
Serialize-List $ list
@(&#34; A&#34;&#34; B&#34;&#34; C&#34)
...但是当你通过管道传递它时没那么多:
$ list |序列化-列表
@(&#34; C&#34)
但是使用begin,process和end blocks重构你的函数:
# Serialize-List
param
(
[Parameter(Mandatory, ValueFromPipeline)]
[string[]]$list
)
begin
{
$output = "@(";
}
process
{
foreach ($element in $list)
{
$output += "`"$element`","
}
}
end
{
$output = $output.Substring(0, $output.Length - 1)
$output += ")"
$output
}
......你可以双向获得所需的输出。
Serialize-List $ list
@(&#34; A&#34;&#34; B&#34;&#34; C&#34)
$ list |序列化-列表
@(&#34; A&#34;&#34; B&#34;&#34; C&#34)
答案 3 :(得分:1)
$ar="1","2","3"
$ar | foreach { $_ }