如何在 Powershell 管道中引用上一个"pipe"的输出?



我写这段代码来获取一些(相对(文件路径:

function Get-ExecutingScriptDirectory() {
return Split-Path $script:MyInvocation.MyCommand.Path  # returns this script's directory
}
$some_file_path = Get-ExecutingScriptDirectory | Join-Path -Path $_ -ChildPath "foo.json"

这引发了错误:

Join-Path : Cannot bind argument to parameter 'Path' because it is null.
+ $some_file_path  = Get-ExecutingScriptDirectory | Join-Path -Path $_ -ChildPath "fo ...
+                                                     ~~
+ CategoryInfo          : InvalidData: (:) [Join-Path], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.JoinPathCommand

这向我表明Get-ExecutingScriptDirectory的输出为 null - 但事实并非如此 - 当我像这样写出脚本时,没问题:

$this_directory = Get-ExecutingScriptDirectory
$some_file_path = Join-Path -Path $this_directory -ChildPath "foo.json"

所以问题是$_是空的。 我希望$_引用前一个管道的标准输出。 MSDN 文档也提出了这一点,但随后它似乎立即自相矛盾:

$_ 包含管道对象中的当前对象。您可以在对管道中的每个对象或选定对象执行操作的命令中使用此变量。

在我的代码上下文中,$_似乎有资格称为"管道对象中的当前对象" - 但我没有将其与对管道中的每个对象或选定对象执行操作的命令一起使用。

$$$^看起来很有希望,但 MSDN 文档只是在这里说了一些关于词汇标记的模糊内容。 关于$PSItem的文档同样简洁。

我实际上做的是创建一个大管道:

$some_file_path = Get-ExecutingScriptDirectory | Join-Path -Path {{PREVIOUS STDOUT}} -ChildPath "foo.json" | Get-Content {{PREVIOUS STDOUT}} | Convert-FromJson {{PREVIOUS STDOUT}} | {{PREVIOUS STDOUT}}.data

我想知道我在概念和技术层面上哪里出错了。

下面是一个简单的例子。 在文档中搜索"接受管道输入"。 使用带有 get-content 的 -path 参数的脚本块有点高级。 大多数人使用 foreach-object 代替。 它之所以有效,是因为 -path 接受管道输入,但仅接受属性名称。 join-path 的 -path 参数可以按值位于管道上,因此更容易。 一旦你理解了它,这将派上用场。 也许有时尝试一下会更容易。

echo '"hi"' > foo.json
'.' | Join-Path -ChildPath foo.json | Get-Content -Path { $_ } | ConvertFrom-Json
hi

或者使用 foreach,在这种情况下是 foreach-object 的缩写。 但是 $_ 必须始终位于大括号内。

'.' | Join-Path -ChildPath foo.json | foreach { Get-Content $_ } | ConvertFrom-Json

您可以通过执行以下命令来执行所需的操作:

(Get-Content -Path (Get-ExecutingScriptDirectory | Join-Path -ChildPath "foo.json" | ConvertFrom-Json)).data

某些命令支持管道参数绑定。选项是按值的管道或按属性的管道。参数绑定的一个很好的参考是关于函数高级参数。

联机搜索要使用的命令将生成参数绑定信息。例如,联接路径具有参数部分。每个参数都有一个描述,包括字段Accept pipeline input:。要使参数接受管道输入,必须True。通常,它会说明如何将值传递到管道中(ByPropertyNameByValue(。

ByPropertyName指示必须输出包含与参数名称匹配的属性名称的对象。然后,一旦对象通过管道传输,参数将绑定到匹配属性名称的值。有关示例,请参见下文:

$filePath = [pscustomobject]@{Path = 'c:temptest1t.txt'}
$filePath
Path
----
c:temptest1t.txt
$filePath.Path # This binds to -Path in Get-Content
c:temptest1t.txt
$filepath | Get-Content 

ByValue指示管道传入的任何值都将尝试绑定到该参数。如果在绑定时存在类型差异,则可能会引发错误。例如,请参阅下文:

"c:temp" | Join-Path -ChildPath "filepath" # c:temp binds to `-Path`
c:tempfilepath

关于$_,它是$PSItem的同义词,是脚本块中的当前输入对象。您通常会看到它与Foreach-ObjectWhere-Object一起使用。如果没有脚本块,您将无法使用$_

从技术上讲,您可以将任何内容传送到Foreach-ObjectWhere-Object。然后当前管道对象将由$_表示。您不需要集合,因为单个项目可以通过管道传入。见下文:

"c:temp" | Foreach-Object { $_ }
c:temp
$filePath | Foreach-Object { $_ }
Path
----
c:temptest1t.txt
$filePath | Foreach-Object { $_.Path }
c:temptest1t.txt

只需使用代码块。

function Get-ExecutingScriptDirectory() {
return Split-Path $script:MyInvocation.MyCommand.Path  # returns this script's directory
}
$some_file_path = Get-ExecutingScriptDirectory | Join-Path -Path {$_} -ChildPath "foo.json"
$some_file_path 
read-host

它在此代码中不起作用的原因@ get-content是因为它在那里评估为假。

Get-ExecutingScriptDirectory | Join-Path -Path {$_} -ChildPath "foo.json" | Get-Content {$_} and Get-ExecutingScriptDirectory | Join-Path -Path {$_} -ChildPath "foo.json" | Get-Content $_

如果对象的计算结果为 $True,则只能使用 $_ 或 $psItem 传递对象。

这就是它在第一个示例中工作的原因。

function Get-ExecutingScriptDirectory() {
return Split-Path $script:MyInvocation.MyCommand.Path  # returns this script's directory
}
if(Get-ExecutingScriptDirectory -eq $True){
write-host This is true
}
Output: This is true

您也可以使用 Parethesis 来隔离管道中的对象。

例:

Get-Content (Get-ExecutingScriptDirectory | Join-Path -Path {$_} -ChildPath "foo.json")

"|"处理其左侧的对象,因此执行 get-content | get-content | 对脚本没有意义。如果要执行类似操作,则需要将其分隔为带有分号的多个命令。或者使用"Foreach"cmdlet。

gc (Get-ExecutingScriptDirectory | Join-Path -Path {$_} -ChildPath "foo.json");gc (Get-ExecutingScriptDirectory | Join-Path -Path {$_} -ChildPath "bar.json")

最新更新