PowerShell:Start作业中的$input到底是什么?
考虑以下代码。我只是使用PowerShell:Start作业中的$input到底是什么?,powershell,windows-8.1,powershell-4.0,Powershell,Windows 8.1,Powershell 4.0,考虑以下代码。我只是使用-InputObject参数将一个32位有符号整数数组[Int32[]]传入启动作业cmdlet $Job = Start-Job -ScriptBlock { $input.GetType().FullName; } -InputObject @(1,2,3); Wait-Job -Job $Job; Receive-Job -Keep $Job; 该代码的结果是: System.Management.Automation.Runspaces.PipelineRead
-InputObject
参数将一个32位有符号整数数组[Int32[]]
传入启动作业
cmdlet
$Job = Start-Job -ScriptBlock { $input.GetType().FullName; } -InputObject @(1,2,3);
Wait-Job -Job $Job;
Receive-Job -Keep $Job;
该代码的结果是:
System.Management.Automation.Runspaces.PipelineReader`1+<GetReadEnumerator>d__0[[System.Object, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
但是,我收到了一条错误消息:
方法调用失败,因为[System.Int32]不包含名为“ReadToEnd”的方法。
+CategoryInfo:InvalidOperation:(:)[],运行时异常
+FullyQualifiedErrorId:MethodNotFound
+PSComputerName:localhost
然后我想,我将使用PSBase
属性来获取“真实”对象
但随后我收到一条类似的错误消息:
方法调用失败,因为[System.Management.Automation.PSInternalMemberSet]不包含名为“ReadToEnd”的方法。
+CategoryInfo:InvalidOperation:(ReadToEnd:String)[],运行时异常
+FullyQualifiedErrorId:MethodNotFound
+PSComputerName:localhost
我注意到在这种困惑周围有一种神秘感,但它让我更加困惑。显然,PipelineReader
类有一个名称混乱的属性4\u this
,它有一个Read()
方法,使用Get Member
实际上看不到该方法
底线:当通过启动作业
cmdlet上的-InputObject
参数提交输入时,是否有人知道如何简单地“展开”$input
自动变量的内容,以便我可以单独处理对象
这个脚本应该只返回1
,而不是1、2、3
$Job = Start-Job -ScriptBlock { $input[0]; } -InputObject @(1,2,3);
Wait-Job -Job $Job;
Receive-Job -Keep $Job;
资料来源:
总之:$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
更新:这里有证据证明这也适用于您的启动作业
场景。对样本进行注释以解释
$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
并证明我关于管道的“理论”。以下是流水线版本:
$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
所以我坚持我最初的答案。行为相同,您只是以不同的方式使用管道/cmdlet。:) 大概
$input
是一个枚举器,就像在标准管道中一样。
为了处理项目,我们应该使用带有
自动变量$\uuu
或在端的另一个管道中传递$input
块(如果未指定,则隐式)
也许还有其他方法可以枚举$input
的项,但它们是
据我所知,在实践中不经常使用。这似乎有效:
$Job = Start-Job -ScriptBlock { $input.movenext();$input.current[0] } -InputObject @(1,2,3);
Wait-Job -Job $Job;
Receive-Job -Keep $Job;
$Job=Start Job-ScriptBlock{$($input)[0];}-InputObject@(1,2,3)
对你有用吗?是的,但是你能进一步解释一下$input
是什么吗?这就是我最终想要理解的。我想我有一个更好的例子。指示枚举器中的$input
,不能像数组那样对其进行索引。请尝试以下操作:$Job=Start Job-ScriptBlock{$input.getEnumerator()[0]}-InputObject@(1,2,3)
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
$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
# 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 | %{$_}}
$Job = Start-Job -ScriptBlock { $input.movenext();$input.current[0] } -InputObject @(1,2,3);
Wait-Job -Job $Job;
Receive-Job -Keep $Job;