首页 > 解决方案 > PowerShell 将多行与正则表达式模式匹配

问题描述

我编写了一个 Powershell 脚本和正则表达式来搜索两个配置文本文件以查找管理 Vlan 的匹配项。例如,每个文本文件有两个管理 vlan,配置如下:

配置1.txt

123 MGMT_123_VLAN                  
234 MGMT_VLAN_234

配置2.txt

890 MGMT_VLAN_890
125 MGMT_VLAN_USERS

下面是我的脚本。它有几个问题。

首先,如果我使用 运行脚本,$Mgmt_vlan = Select-String -Path $File -Pattern $String -AllMatches则屏幕输出显示预期的四 (4) 个 Mgmt vlan,但在 CSV 文件中输出显示如下

Filename                          Mgmt_vlan
Config1.txt                       System.Object[]
Config2.txt                       System.Object[]

我运行了脚本,控制台屏幕上的输出正好显示了我期望的四 (4) 个管理 vlan,但在 CSV 文件中却没有。它只显示这些 vlan

其次,如果我运行脚本$Mgmt_vlan = Select-String -Path $File -Pattern $String | Select -First 1

然后CSV显示如下:

Filename                          Mgmt_vlan
Config1.txt                       123 MGMT_123_VLAN 
Config2.txt                       890 MGMT_VLAN_890

第二种方法Select -First 1似乎只选择文件中的第一个匹配项。我尝试将其更改为Select -First 2,然后 CSV 将 Mgmt_Vlan 列显示为System.Object[].

屏幕上的结果输出准确地显示了四 (4) 个 Mgmt Vlan,如预期的那样。

$folder = "c:\config_folder"
$files = Get-childitem $folder\*.txt

Function find_management_vlan($Text)
{
    $Vlan = @()
    foreach($file in files) {
        Mgmt_Vlan = Select-String -Path $File -Pattern $Text -AllMatches
        if($Mgmt_Vlan)  # if there is a match
        {
            $Vlan += New-Object -PSObject -Property @{'Filename' = $File; 'Mgmt_vlan' = $Mgmt_vlan}
            $Vlan | Select 'Filename', 'Mgmt_vlan' | export-csv C:\documents\Mgmt_vlan.csv
            $Mgmt_Vlan             # test to see if it shows correct matches on screen and yes it did
        }
        else
        {
            $Vlan += New-Object -PSObject -Property @{'Filename' = $File; 'Mgmt_vlan' = "Mgmt Vlan Not Found"}
            $Vlan | Select 'Filename', 'Mgmt_vlan' | Export-CSV C:\Documents\Mgmt_vlan.csv
        }
     }
 }
 
 find_management_vlan "^\d{1,3}\s.MGMT_"

标签: regexpowershell

解决方案


正则表达式校正

首先,这段代码有很多错误。所以这可能不是您实际使用的代码。

其次,该模式不会匹配您的字符串,因为如果您使用"^\d{1,3}\s.MGMT_",您将匹配 1-3 个数字、任何空白字符(等于 [\r\n\t\f\v ])、任何字符(行终止符除外)和 MGMT_ 字符以及之后的任何内容。所以不是你想要的。因此,在您的情况下,您可以使用例如 this:^\d{1,3}\sMGMT_或 with\s+进行多个匹配。

代码更正

  1. 现在回到您的代码...您创建数组 $Vlan,没关系。

  2. 之后,您尝试获取所有字符串(在您的情况下,从目录中的每个文件中获取 2 个字符串)并使用两个复杂对象创建 PSObject。一个是 System.IO 中的 FileInfo,第二个是 System.IO 中的字符串数组 (String[])。.ToString()在正在处理的对象的每个属性上调用Export-Csv 函数。如果你在一个数组(即 Mgmt_vlan)上调用 .ToString() ,你会得到"System.Object[]",按照默认实现。因此,如果要从中制作 csv,则必须拥有一组“平面”对象。

  3. 第二个大错误是创建一个具有多个职责的函数。在您的情况下,您的功能负责收集数据,然后负责导出数据。这是一个很大的不。因此,修复您的代码并将该导出移到其他地方。例如,您可以使用类似这样的东西(我使用了 get-content,因为我更喜欢它,但您可以使用任何您想要获取字符串集合的内容。

    function Get-ManagementVlans($pattern, $files)
    {
        $Vlans = @()
        foreach ($file in $files)
        {
            $matches = (Get-Content $file.FullName -Encoding UTF8).Where({$_ -imatch $pattern})
            if ($matches)
            {
                $Vlans += $matches | % { New-Object -TypeName PSObject -Property @{'Filename' = $File; 'Mgmt_vlan' = $_.Trim()}  }
            }
            else
            {
                $Vlans += New-Object -TypeName PSObject -Property @{'Filename' = $File; 'Mgmt_vlan' = "Mgmt Vlan Not Found"}
            }
        }
    
        return $Vlans
    }
    
    function Export-ManagementVlans($path, $data)
    {
        #do something...
        $data | Select Filename,Mgmt_vlan | Export-Csv "$path\Mgmt_vlan.csv" -Encoding UTF8 -NoTypeInformation
    }
    
    $folder = "C:\temp\soHelp"
    $files = dir "$folder\*.txt"
    
    $Vlans = Get-ManagementVlans -pattern "^\d{1,3}\sMGMT_" -files $files
    $Vlans
    Export-ManagementVlans -path $folder -data $Vlans```
    
    

概括

但在我看来,在这种情况下是过度编程来创建像你一样的东西。您可以在 oneliner 中轻松完成(但如果文件不包含任何内容,则您没有信息)。powershell 的强大之处在于:

$pattern = "^\d{1,3}\s+MGMT_"
$path = "C:\temp\soHelp\"
dir $path -Filter *.txt -File | Get-Content -Encoding UTF8 | ? {$_ -imatch $pattern} | select @{l="FileName";e={$_.PSChildName}},@{l="Mgmt_vlan";e={$_}} | Export-Csv -Path "$path\Report.csv" -Encoding UTF8 -NoTypeInformation

或使用选择字符串:

dir $path -Filter *.txt -File | Select-String -Pattern $pattern -AllMatches | select FileName,@{l="Mgmt_vlan";e={$_.Line}} | Export-Csv -Path "$path\Report.csv" -Encoding UTF8 -NoTypeInformation

推荐阅读