我希望在脚本中有一个函数,可以使用作为 predicate 或Where-Object
传入的ScriptBlock。
我会写
cat .\.gitignore | Where-Object { $_.contains('pp') }
这是可行的如:
$f = { $_.contains('pp') }; cat .gitignore | Where-Object $f
无论多么艰难
$f.Invoke( 'apple' )
导致
方法调用异常:使用“1”个参数调用“Invoke”时发生异常:“不能对空值表达式调用方法。
而我期望的是True
,所以很明显$_
没有设置。
我也是
$ff = { echo "args: $args`nauto: $_" }; $ff.Invoke( 'apple' )
产出
args: apple
auto:
因此$_
显然没有设置好。
'apple' | %{ $_.contains('pp') }
可以,但我希望脚本块是一个变量
$f = { $_.contains('pp') }; 'apple' | %$f
是编译错误。
**tl;dr:**那么我如何在我调用的脚本块中设置/传递$_
的值呢?
3条答案
按热度按时间31moq8wy1#
请注意,此答案仅涉及如何在脚本块的
process
块的上下文中填充$_
。其他用例可在about_PSItem文档中找到。在Script Block的
process
块的上下文中,$_
($PSItem
)变量被自动填充并且表示来自管道的每个元素,即:但是,您可以使用ScriptBlock Class中的
InvokeWithContext
method实现相同的效果:请注意,此方法**始终返回[
Collection
1](https://learn.microsoft.com/en-us/dotnet/api/system.collections.objectmodel.collection-1?view=net-7.0)**。输出未枚举。 值得注意的是,[zett42](https://stackoverflow.com/users/7571258/zett42)指出,通过其方法或通过调用操作符
&`调用的脚本块的作用域规则仍然适用。脚本块能够看到父作用域变量(不包括Remoting):
但无法更新它们:
除非使用作用域修饰符(仅适用于Value Types):
或通过点采购操作员
.
:有关详细信息,请参见**about Scopes**。
62o28rlo2#
**最好避免使用
.Invoke()
方法(及其变体.InvokeReturnAsIs()
和.InvokeWithContext()
)在PowerShell代码中执行script block a *,因为它在几个方面更改了调用的语义a有关详细信息,请参阅this answer。虽然PowerShell惯用的等价物是
&
(调用运算符),但在这里还 * 不够 *,因为您希望在脚本块中定义自动$_
变量。基于输入定义
$_
最简单的方法确实是ForEach-Object
(它的一个内置别名是**%
**):然而,请注意,
-InputObject
仅对 * 单个 * 输入对象有效(尽管您可以传递数组/集合,在这种情况下$_
将其作为 * 一个整体 * 引用);要提供多个,请使用管道:相反,如果你的意图只是让你的脚本块接受 * 参数 *,你根本不需要
$_
,你可以简单地让你的脚本要么 * 正式声明参数*要么使用自动$args
变量,它包含所有(未绑定的)位置参数:有关参数声明语法的更多信息,请参见概念性
about_Functions
帮助主题(脚本块基本上是未命名的function
,并且只能在脚本块中使用param(...)
声明样式)。9o685dep3#
我通过将
$f
Package 为()
使其工作,如下所示或者(感谢@zett42)在
%
和$
之间放置一个空格,如甚至可以从变量传入值
或者在
If
-语句中使用它所以看起来
$_
只能通过"管道“(aka\
)来设置吗?但是,为什么要这样做,它是如何工作的,以及是否可以通过.invoke()
来完成,我都不知道。如果有人能解释这一点,请解释。从What does $_ mean in PowerShell?和相关文档来看,
$PSItem
似乎确实是一个更好的名称,因为它不像Perl's$_