【问题标题】:Powershell, how to capture argument(s) of Select-String and include with matched outputPowershell,如何捕获 Select-String 的参数并包含匹配的输出
【发布时间】:2020-07-14 16:03:44
【问题描述】:

感谢@mklement0 提供的帮助,并在Powershell search directory for code files with text matching input a txt file 中给出了答案。

下面的 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”?

玩了火柴对象,但它似乎没有信息。也尝试过像这里一样的管道变量,但 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

谢谢。

【问题讨论】:

    标签: powershell select-string


    【解决方案1】:

    Select-String 输出的Microsoft.PowerShell.Commands.MatchInfo 实例具有一个Pattern 属性,该属性反映了传递给-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 属性中反映首先出现在输入行的实际模式,还需要做更多工作:

    • 使用 alternation (|) 将您的模式数组形成一个单个正则表达式,并作为一个整体包裹在一个捕获组中( (...)) - 例如,'(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 在每一行查找所有 个匹配项,表示在MatchInfo 输出对象的.Matches 集合中。

    • 然后必须枚举.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 蹒跚学步的孩子,而不是新生儿。
    • @TomChickory :) 很高兴听到这个消息;我的荣幸。
    【解决方案2】:

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

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

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

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

    $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}
    

    【讨论】:

      猜你喜欢
      • 2023-03-23
      • 1970-01-01
      • 2017-12-16
      • 1970-01-01
      • 2012-05-10
      • 2021-07-30
      • 2021-05-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多