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

Sha*_*tin 7 powershell code-readability

原始问题

我管道一个字符串并处理For-EachObject如下:

 "Test" | % { $_.Substring(0,1) }
Run Code Online (Sandbox Code Playgroud)

使用单个管道项目似乎是错误的For-EachObject,部分原因是它对未来的代码维护者有误导性.但是,我不知道任何其他方式来捕捉字符串,同时说"它只是一个单项".例如,这不起作用.

"Test" | $_.Substring(0,1)
"Test" | { $_.Substring(0,1) }
Run Code Online (Sandbox Code Playgroud)

如何处理单个对象,同时表明我只期望一个?

编辑:添加实际用例

以上是我实际想要完成的简化版本.我得到了维基百科文章的第一段,它是将结果保存到文件的更大函数的一部分.

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 '<[^>]*>'
     } 
Run Code Online (Sandbox Code Playgroud)

需要处理单个对象的部分遵循select -expand innerHtml表达式.管道是我的首选方式,因为在curl部件周围放置多个括号似乎很难看.

别名

  • curlInvoke-WebRequest
  • selectSelect-Object
  • -expandExplandProperty
  • ?Where-Object
  • %For-EachObject

Rya*_*ose 6

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

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

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

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

这是一个很常见的函数,PowerShell有一个简写,用于编写一个从流水线中获取一个参数并且只包含一个流程块的函数.

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