如何像"sed"一样只输出Powershell中的第一个或所有匹配项



sed中,可以输出所有匹配项,例如仅输出第一个:

$ echo -e 'a1nb2nb3'
a1
b2
b3
# print all matches
$ echo -e 'a1nb2nb3' | sed -n '/b(.)/s//1/p'
2
3
# print only first match
$ echo -e 'a1nb2nb3' | sed -n '0,/b(.)/s//1/p'
2

如何使用Powershell执行此操作?

我只得到第一个匹配:

@'
>> a1
>> b2
>> b3
>> '@ | Select-String 'b(.*)' | ForEach-Object{$_.Matches.Groups[1].Value}
2
  • 您的PowerShell此处字符串(@'<newline>...<newline>'@(是单个对象(字符串(,恰好是多行字符串

  • 对于Select-String;行";,并且默认情况下,它只在每个"em"上查找第一个匹配;行"-除非指定-AllMatches开关。

    • 只有在以下情况下,输入才是隐式
      • Select-String本身读取并处理带有-Path-LiteralPath参数的文件
      • 使用Get-Content输出作为输入,默认情况下逐行流式传输(尽管使用Select-String-Path/-LiteralPath或管道Get-ChildItem输出要高效得多(
      • 从调用到外部程序的管道输出,这些程序的stdout输出也是逐行流式传输的
  • 由于-AllMatches存在并且多个对象存储在.Matches集合中,成员访问枚举操作$_.Matches.Groups[1].Value不足以获得每个匹配的.Groups[1].Value属性-您需要迭代$_.Matches集合并将.Groups[1].Value应用于每个元素。

因此,要获得所有匹配

@'
a1
b2
b3
'@ |
  Select-String 'b(.*)' -AllMatches |
  ForEach-Object{ $_.Matches.ForEach({ $_.Groups[1].Value }) }

输出:

2
3

为了只获得第一个匹配,您的命令按原样工作,原因如上所述。


或者,您可以让先将此处字符串拆分为单独的行。在这种情况下,您的命令的其余部分将按原样工作,以获得所有匹配

@'
a1
b2
b3
'@ -split 'r?n' |  # Split the multi-line string into indiv. lines
  Select-String 'b(.*)' |
  ForEach-Object{ $_.Matches.Groups[1].Value }

要获得第一个匹配,并逐行输出,请将以上内容通过管道传输到Select-Object -First 1

注意:Select-String有一个-List开关,它最多查找一个匹配,但它只适用于文件作为输入,可以通过它自己的-Path/-LiteralPath参数,也可以通过Get-ChildItem中的管道文件信息对象。

最新更新