管道单个对象并在没有 Foreach 对象的情况下处理它

Pipe a single object and process it without For-EachObject

原问题

我通过管道传输单个字符串并使用 For-EachObject 对其进行处理,如下所示:

 "Test" | % { $_.Substring(0,1) }

使用 For-EachObject 处理单个管道项目似乎是错误的,部分原因是它会误导未来的代码维护者。不过,我不知道还有什么其他方法可以在说 "it's just a single item." 的同时捕获字符串。例如,这不起作用。

"Test" | $_.Substring(0,1)
"Test" | { $_.Substring(0,1) }

如何在指示我只期望一个对象的同时处理单个对象?

编辑:添加实际用例

以上是我实际尝试完成的简化版本。我正在获取维基百科文章的第一段,它是 a larger function that saves the result to a file.

的一部分
curl "www.wikipedia.org/wiki/Hope,_British_Columbia" | 
    select -expand allelements | 
    ? { $_.id -eq "mw-content-text" } | 
    select -expand innerHTML | 
    % { 
        $i = $_.IndexOf("<P>"); 
        $j = $_.IndexOf("</P>"); 
        $_.Substring($i, $j - $i) -replace '<[^>]*>'
     } 

需要处理单个对象的部分在select -expand innerHtml表达式之后。管道是我的首选方式,因为在 curl 部分周围放置多个括号看起来很难看。

别名

如果您正在创建单一用途的代码,您可以同时控制输入和输出,并且始终只有一个对象,那么使用管道就太过分了,而且不太合适。只需将字符串作为参数传递给您的函数即可。

function f([String]$s) {
  $s.Substring(0,1)
}
PS> f "Test"
T

如果您要构建通用函数以从管道获取输入,则您的函数需要考虑流中的多个对象。幸运的是,PowerShell 有一种使用 Process{} 块的自然方式来执行此操作,该块对输入管道中的每个项目执行一次。

function f {
  param(
    [Parameter(ValueFromPipeline=$true)]
    [String]$item
  )
  process {
    $item.Substring(0,1)
  }
}
PS> '123','abc','#%@' | f
1
a
#

这是一个足够常见的函数,PowerShell 有一个 shorthand 用于编写一个从管道获取一个参数并且只包含一个进程块的函数。

filter f {
  $_.SubString(0,1)
}
PS> '123','abc','#%@' | f
1
a
#