5 powershell windows-8.1 powershell-4.0
考虑以下代码。我只是使用参数将 32 位有符号整数数组传递到 cmdlet[Int32[]]中。Start-Job-InputObject
$Job = Start-Job -ScriptBlock { $input.GetType().FullName; } -InputObject @(1,2,3);
Wait-Job -Job $Job;
Receive-Job -Keep $Job;
Run Code Online (Sandbox Code Playgroud)
这段代码的结果是:
System.Management.Automation.Runspaces.PipelineReader`1+<GetReadEnumerator>d__0[[System.Object, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
Run Code Online (Sandbox Code Playgroud)
查看PipelineReader .NET 类的文档,它有一个ReadToEnd()方法。因此,以下代码应该可以工作:
$Job = Start-Job -ScriptBlock { $input.ReadToEnd(); } -InputObject @(1,2,3);
Wait-Job -Job $Job;
Receive-Job -Keep $Job;
Run Code Online (Sandbox Code Playgroud)
但相反,我收到一条错误消息:
方法调用失败,因为 [System.Int32] 不包含名为“ReadToEnd”的方法。+ CategoryInfo : InvalidOperation: (:) [], RuntimeException + FullQualifiedErrorId : MethodNotFound + PSComputerName : localhost
所以我想,我将使用该PSBase属性来获取“真实”对象。
$Job = Start-Job -ScriptBlock { $input.psbase.ReadToEnd(); } -InputObject @(1,2,3);
Wait-Job -Job $Job;
Receive-Job -Keep $Job;
Run Code Online (Sandbox Code Playgroud)
但随后我收到类似的错误消息:
方法调用失败,因为 [System.Management.Automation.PSInternalMemberSet] 不包含名为“ReadToEnd”的方法。+ CategoryInfo : InvalidOperation: (ReadToEnd:String) [], RuntimeException + ExcellentQualifiedErrorId : MethodNotFound + PSComputerName : localhost
我注意到围绕这种混乱提出了一个 Microsoft Connect 错误,但这让我更加困惑。显然,该类PipelineReader有一个名称令人困惑的属性<>4__this,它有一个Read()方法,您实际上无法通过使用来看到该方法Get-Member。
底线:当通过 cmdlet上的参数$input提交输入时,有谁知道如何简单地“解开”自动变量的内容,以便我可以单独处理对象?-InputObjectStart-Job
该脚本应该简单地返回1,而不是1, 2, 3.
$Job = Start-Job -ScriptBlock { $input[0]; } -InputObject @(1,2,3);
Wait-Job -Job $Job;
Receive-Job -Keep $Job;
Run Code Online (Sandbox Code Playgroud)
大概$input是一个枚举器,就像在标准管道中一样。为了处理项目,我们应该使用process带有自动变量的块$_,或者$input在块中传递另一个管道end
(如果未指定,则隐式)。
# process each item separately
$Job = Start-Job -ScriptBlock {process{$_}} -InputObject @(1,2,3);
Wait-Job -Job $Job;
Receive-Job -Keep $Job;
# process the whole $input
$Job = Start-Job -ScriptBlock {$input | %{$_}} -InputObject @(1,2,3);
Wait-Job -Job $Job;
Receive-Job -Keep $Job;
# compare with script blocks in standard pipelines
# each item
@(1,2,3) | . {process{$_}}
# whole input
@(1,2,3) | . {$input | %{$_}}
Run Code Online (Sandbox Code Playgroud)
也许还有其他方法来枚举项目,$input但据我所知,它们在实践中并不经常使用。
Run Code Online (Sandbox Code Playgroud)$Input Contains an enumerator that enumerates all input that is passed to a function. The $input variable is available only to functions and script blocks (which are unnamed functions). In the Process block of a function, the $input variable enumerates the object that is currently in the pipeline. When the Process block completes, there are no objects left in the pipeline, so the $input variable enumerates an empty collection. If the function does not have a Process block, then in the End block, the $input variable enumerates the collection of all input to the function.
总结一下:$input是一个自动变量,以枚举器的形式包含整个管道,与$_管道中的“当前对象”不同。
这是如何使用它的示例。
function test {
#$input is an enumerator that you should use $input | foreach-object { } to access the objects.
#To to get all items you could e.g. convert the enumerator to an array.
$arr = @($input)
#If you need to use the $input enumerator for something else, you need to call .Reset() first as the enumerator has reached the end.
$input.Reset()
#Print some values from the data
$arr.count
$arr[0]
}
PS> "hello", "world" | test
2
hello
Run Code Online (Sandbox Code Playgroud)
更新:这是这也适用于您的场景的证据Start-Job。对示例进行注释以进行解释。
$Job = Start-Job -ScriptBlock {
#Read the complete pipeline to an array
$data= @($input)
"`$data is an $($data.GetType().Name) with $($data.count) objects"
#Unlike in a pipeline, where the `Start-Job` command would be called once per object like `Start-Job ...... -InputObject $_`,
#you're inputing a single `object[]` object the the pipeline. So you only have one item in your $input pipeline.
#Get our inputobject (our array)
$arr= $data[0]
"`$arr is an $($arr.GetType().Name)"
#Use array
"$($arr[0]) is less than $($arr[1]) which is less than $($arr[2])"
} -InputObject @(1,2,3);
Wait-Job -Job $Job;
Receive-Job -Keep $Job;
Id Name PSJobTypeName State HasMoreData Location Command
-- ---- ------------- ----- ----------- -------- -------
54 Job54 BackgroundJob Completed True localhost ...
$data is an Object[] with 1 objects
$arr is an ArrayList
1 is less then 2 which is less then 3
Run Code Online (Sandbox Code Playgroud)
并证明我关于管道的“理论”。这是管道版本:
$Job = 1, 2, 3 | Start-Job -ScriptBlock {
#Read the complete pipeline to an array
$data= @($input)
"`$data is an $($data.GetType().Name) with $($data.count) objects"
#Now the command is run per object, so the $input enumerator contained our 3 seperate Int32 values.
#Get a single object in the pipeline
$OneOfTheValues= $data[0]
"`$OneOfTheValues is an $($OneOfTheValues.GetType().Name)"
#Use data
"$($data[0]) is less than $($data[1]) which is less than $($data[2])"
}
Wait-Job -Job $Job;
Receive-Job -Keep $Job;
Id Name PSJobTypeName State HasMoreData Location Command
-- ---- ------------- ----- ----------- -------- -------
58 Job58 BackgroundJob Completed True localhost ...
$data is an Object[] with 3 objects
$OneOfTheValues is an Int32
1 is less then 2 which is less then 3
Run Code Online (Sandbox Code Playgroud)
所以我坚持我原来的答案。行为是相同的,您只是以不同的方式使用管道/cmdlet。:)
| 归档时间: |
|
| 查看次数: |
4759 次 |
| 最近记录: |