32

ファイルから特定の構成ブロック(複数の構成ブロック)を一致させようとすると、いくつかの問題が発生します。以下は、設定ファイルから抽出しようとしているブロックです。

ap71xx 00-01-23-45-67-89
 use profile PROFILE
 use rf-domain DOMAIN
 hostname ACCESSPOINT
 area inside
!

このようなものが複数あり、それぞれが異なるMACアドレスを持っています。複数の行にまたがって構成ブロックを一致させるにはどうすればよいですか?

4

4 に答える 4

62

遭遇する可能性のある最初の問題は、複数の行にまたがって一致させるために、ファイルの内容を個々の行ではなく単一の文字列として処理する必要があることです。たとえば、Get-Contentを使用してファイルの内容を読み取る場合、デフォルトでは、文字列の配列(各行に1つの要素)が提供されます。行間で一致させるには、ファイルを1つの文字列にする必要があります(ファイルが大きすぎないことを願っています)。あなたはそのようにこれを行うことができます:

$fileContent = [io.file]::ReadAllText("C:\file.txt")

または、PowerShell 3.0では、次の-Rawパラメーターを指定してGet-Contentを使用できます。

$fileContent = Get-Content c:\file.txt -Raw

次に、ラインターミネータ間で一致する正規表現オプションを指定する必要があります。

  • シングルラインモード(改行を含む.すべての文字に一致)、および
  • マルチラインモード(^および$埋め込みラインターミネータと一致)、例:
  • (?smi)-「i」は大文字と小文字を区別しないことに注意してください

例えば:

C:\> $fileContent | Select-String '(?smi)([0-9a-f]{2}(-|\s*$)){6}.*?!' -AllMatches |
        Foreach {$_.Matches} | Foreach {$_.Value}

00-01-23-45-67-89
 use profile PROFILE
 use rf-domain DOMAIN
 hostname ACCESSPOINT
 area inside
!
00-01-23-45-67-89
 use profile PROFILE
 use rf-domain DOMAIN
 hostname ACCESSPOINT
 area inside
!

コマンドレットを使用Select-Stringして検索を実行します。指定する-AllMatchesと、すべての一致が出力されますが、-matchオペレーターは最初の一致後に停止します。一致するかどうかを判断するだけでよいブール演算子であるため、理にかなっています。

于 2012-09-24T21:48:35.190 に答える
6

これがまだ誰かにとって価値があるかもしれない場合、そして実際の要件に応じて、キースの答えの正規表現はそれほど複雑である必要はありません。ユーザーが単に各ブロックを出力したい場合は、以下で十分です。

$fileContent = [io.file]::ReadAllText("c:\file.txt")
$fileContent |
    Select-String '(?smi)ap71xx[^!]+!' -AllMatches |
    %{ $_.Matches } |
    %{ $_.Value }

正規表現のap71xx[^!]*!パフォーマンスは向上し.*ます。予期しない結果が生じる可能性があるため、正規表現での使用はお勧めしません。パターン[^!]+!は、感嘆符とそれに続く感嘆符を除くすべての文字に一致します。

ブロックの開始が出力で必要ない場合、更新されたスクリプトは次のとおりです。

$fileContent |
    Select-String '(?smi)ap71xx([^!]+!)' -AllMatches |
    %{ $_.Matches } |
    %{ $_.Groups[1] } |
    %{ $_.Value }

Groups[0]一致した文字列全体Groups[1]が含まれ、正規表現の括弧内に一致する文字列が含まれます。

それ以上の処理にが必要ない場合$fileContentは、変数を削除できます。

[io.file]::ReadAllText("c:\file.txt") |
    Select-String '(?smi)ap71xx([^!]+!)' -AllMatches |
    %{ $_.Matches } |
    %{ $_.Groups[1] } |
    %{ $_.Value }
于 2015-05-11T02:52:01.743 に答える
2

apこの正規表現は、テキストの後に任意の数の文字と!:で終わる新しい行を検索します。

(?si)(a).+?\!{1}

だから私は少し退屈でした。説明したとおりにテキストファイルを分割するスクリプトを作成しました(表示した行のみが含まれている場合)。キーワード(ap、profile、domain、hostname、またはarea)が含まれていない限り、他のランダムな行で機能する可能性があります。それらをインポートし、各プロパティ(MAC、プロファイル、ドメイン、ホスト名、エリア)を1行ずつチェックして、後で使用できるオブジェクトに配置します。これはあなたが求めていたものではないことは知っていますが、私はそれに取り組んでいたので、うまくいけば、それはいくつかの利益のために使用することができます。興味のある方はこちらのスクリプトをご覧ください。特定のニーズに合わせて調整する必要があります。

$Lines = Get-Content "c:\test\test.txt"
$varObjs = @()
for ($num = 0; $num -lt $lines.Count; $num =$varLast ) {
    #Checks to make sure the line isn't blank or a !. If it is, it skips to next line
    if ($Lines[$num] -match "!") {
        $varLast++
        continue
    }
    if (([regex]::Match($Lines[$num],"^\s.*$")).success) {
        $varLast++
        continue
    }
    $Index = [array]::IndexOf($lines, $lines[$num])
    $b=0
    $varObj = New-Object System.Object
    while ($Lines[$num + $b] -notmatch "!" ) {
        #Checks line by line to see what it matches, adds to the $varObj when it finds what it wants.
        if ($Lines[$num + $b] -match "ap") { $varObj | Add-Member -MemberType NoteProperty -Name Mac -Value $([regex]::Split($lines[$num + $b],"\s"))[1] }
        if ($lines[$num + $b] -match "profile") { $varObj | Add-Member -MemberType NoteProperty -Name Profile -Value $([regex]::Split($lines[$num + $b],"\s"))[3] }
        if ($Lines[$num + $b] -match "domain") { $varObj | Add-Member -MemberType NoteProperty -Name rf-domain -Value $([regex]::Split($lines[$num + $b],"\s"))[3] }
        if ($Lines[$num + $b] -match "hostname") { $varObj | Add-Member -MemberType NoteProperty -Name hostname -Value $([regex]::Split($lines[$num + $b],"\s"))[2] }
        if ($Lines[$num + $b] -match "area") { $varObj | Add-Member -MemberType NoteProperty -Name area -Value $([regex]::Split($lines[$num + $b],"\s"))[2] }
        $b ++
    } #end While
    #Adds the $varObj to $varObjs for future use
    $varObjs += $varObj
    $varLast = ($b + $Index) + 2
}#End for ($num = 0; $num -lt $lines.Count; $num = $varLast)
#displays the $varObjs
$varObjs
于 2012-09-24T22:02:08.083 に答える
0

これが私の見解です。正規表現が必要ない場合は、-likeまたは.contains()を使用できます。質問は、検索パターンが何であるかを決して言いません。これは、Windowsテキストファイルの例です。

$file = (get-content -raw file.txt) -replace "`r"  # avoid the line ending issue

$pattern = 'two
three
f.*' -replace "`r"

# just showing what they really are
$file -replace "`r",'\r' -replace "`n",'\n'
$pattern -replace "`r",'\r' -replace "`n",'\n'

$file -match $pattern

$file | select-string $pattern -quiet 
于 2019-07-04T15:17:45.963 に答える