Powershell,如何捕获 Select-String 的参数并包含匹配的输出

Powershell, how to capture argument(s) of Select-String and include with matched output

感谢@mklement0 帮助我们在 .

中给出答案

下面的 Powershell 可以很好地查找源代码文件夹中出现的一长串数据库字段名称。

$inputFile = 'C:\DataColumnsNames.txt'
$outputFile = 'C:\DataColumnsUsages.txt'
Get-ChildItem C:\ProjectFolder -Filter *.cs -Recurse -Force -ea SilentlyContinue |
  Select-String -Pattern (Get-Content $inputFile) | 
    Select-Object Path, LineNumber, line | 
      Export-csv $outputfile

但是,很多行源代码有多个匹配项,尤其是ADO.NET SQL语句一行有很多字段名。如果字段名称参数包含在匹配输出中,则结果将更直接有用,而无需额外处理,例如将所有内容与原始字段名称列表对齐。例如,如果有源行“BatchId = NewId”,它将匹配字段名列表项“BatchId”。有没有一种简单的方法可以在输出中包含“BatchId”和“BatchId = NewId”?

玩过 matches 对象,但它似乎没有信息。也像这里一样尝试了管道变量,但 X 为空。

$inputFile = 'C:\DataColumnsNames.txt'
$outputFile = 'C:\DataColumnsUsages.txt'
Get-ChildItem C:\ProjectFolder -Filter *.cs -Recurse -Force -ea SilentlyContinue |
  Select-String -Pattern (Get-Content $inputFile -PipelineVariable x) | 
    Select-Object $x, Path, LineNumber, line | 
      Export-csv $outputile

谢谢。

Microsoft.PowerShell.Commands.MatchInfo instances that Select-String 输出有 a Pattern 属性 反映了(潜在)array 中的特定模式在给定行 .

上传递给 -Pattern 并匹配 的模式数

警告如果多个模式匹配,.Pattern只报告其中的模式匹配的是 第一个 其中 -Pattern 参数 .

这是一个简单的例子,使用字符串数组模拟来自文件的行作为输入:

'A fool and',
'his barn',
'are soon parted.',
'foo and bar on the same line' | 
  Select-String -Pattern ('bar', 'foo') | 
    Select-Object  Line, LineNumber, Pattern

以上结果:

Line                         LineNumber Pattern
----                         ---------- -------
A fool and                            1 foo
his barn                              2 bar
foo and bar on the same line          4 bar

请注意 'bar' 如何被列为最后一行的 Pattern 值,即使 'foo' 输入行 中最先出现,因为 'bar' 模式数组 .

之前出现在 'foo' 之前

为了反映首先出现在输入行中的实际模式Pattern属性,需要做更多的工作:

  • 使用 交替 (|) 将模式数组表示为 单个正则表达式 ,包裹作为一个整体在 捕获组 ((...)) - 例如,'(bar|foo)')

    • 注意:下面使用的表达式 '({0})' -f ('bar', 'foo' -join '|') 动态构造此正则表达式,来自数组(这里的数组文字 'bar', 'foo',但您可以替换任何数组变量甚至 (Get-Content $inputFile));如果您想将输入模式视为 文字 并且它们恰好包含正则表达式元字符(例如 .),则需要使用 [regex]::Escape() 对它们进行转义首先.
  • 使用计算的 属性 定义自定义 Pattern 属性 报告捕获组的值,这是每个输入遇到的第一个值行:

'A fool and',
'his barn',
'are soon parted.',
'foo and bar on the same line' | 
  Select-String -AllMatches -Pattern ('({0})' -f ('bar', 'foo' -join '|')) | 
    Select-Object Line, LineNumber, 
                  @{ n='Pattern'; e={ $_.Matches[0].Groups[1].Value } }

这会产生(缩写为仅显示最后一场比赛):

Line                         LineNumber Pattern
----                         ---------- -------
...

foo and bar on the same line          4 foo

现在,'foo' 被正确报告为匹配模式。


报告在每一行所有 模式:

  • 开关 -AllMatches 需要告诉 Select-String 在每一行上找到 所有 匹配项,在 [=40= 中表示] MatchInfo 输出对象的集合。

  • 然后必须枚举 .Matches 集合(通过 .ForEach() 集合方法)以从每个匹配项中提取捕获组值。

'A fool and',
'his barn',
'are soon parted.',
'foo and bar on the same line' | 
  Select-String -AllMatches -Pattern ('({0})' -f ('bar', 'foo' -join '|')) | 
    Select-Object Line, LineNumber, 
                  @{ n='Pattern'; e={ $_.Matches.ForEach({ $_.Groups[1].Value }) } }

这会产生(缩写为仅显示最后一场比赛):

Line                         LineNumber Pattern
----                         ---------- -------
...

foo and bar on the same line          4 {foo, bar}

请注意 'foo''bar' 现在如何在 Pattern 中按照在线遇到的顺序进行报告。

来自@mklement0 的可靠信息和示例足以为我指明正确的方向,以研究和了解有关 Powershell 和对象管道以及计算属性的更多信息。

我终于实现了将 table 和字段名称列表交叉引用到 C# 代码的目标 base.The 输入文件只是 table 和字段名称,管道分隔。 (我遇到的一个小故障是没有在拆分中使用管道,这是一个视觉错误,花了一段时间才终于看到,所以检查一下)。输出是 table 名称、字段名、代码文件名、行号和实际行。它并不完美,但比数百个字段的手动工作要好得多!现在有可能在数据映射和转换项目中进一步实现自动化。考虑过使用 C# 实用程序编程,但这可能需要花同样长的时间来弄清楚和实现,而且比工作的 Powershell 更麻烦。

此时对我来说关键是“工作”!我第一次深入了解 Powershell 的深奥世界。我的解决方案的关键点是使用计算的 属性 来获取输出中的 table 和字段名称,实现表达式可以在某些地方使用,例如构建模式和管道在每个命令之后只传递某些特定的对象(也许这太受限制了,但它比我以前的要好)。

希望这对以后的人有所帮助。我找不到任何足够接近的例子来克服困难,所以问了我的第一个 Whosebug 问题。

$inputFile = "C:\input.txt"
$outputFile = "C:\output.csv"
$results = Get-Content $inputfile
foreach ($i in $results) {
   Get-ChildItem -Path "C:\ProjectFolder"  -Filter *.cs  -Recurse -ErrorAction SilentlyContinue -Force |
   Select-String -Pattern  $i.Split('|')[1] |
    Select-Object   @{ n='Pattern'; e={ $i.Split('|')[0], $i.Split('|')[1]  -join '|'} },  Filename, LineNumber, line |
Export-Csv $outputFile -Append}