特定の正規表現を含むがそれ以上含まないインデントされていない行の下にインデントされたテキストブロックを削除するには、sedをどのように取得できますか?

特定の正規表現を含むがそれ以上含まないインデントされていない行の下にインデントされたテキストブロックを削除するには、sedをどのように取得できますか?

私はほぼ一日中GPT、sed文書、正規表現を扱うのに苦労しています。 Ciscoプレフィックスリスト設定を含むファイルを解析し、指定された正規表現リスト名と一致しないリストを印刷し、そのリストのコンテンツまたは同じリスト名の下にインデントされたコンテンツを無視しようとします。

たとえば、私のファイルは次のようになります(ネットワークの難読化)。

ip prefix-list ispA_in_pref-150
ip prefix-list ispB_in_pref-100
ip prefix-list ispC_out_deny
    seq 10 permit 23.1.24.3/24
ip prefix-list ispD_in_pref-50
    seq 10 permit 5.2.3.4/24
ip prefix-list ispD_in_pref-100
    seq 10 permit 4.18.27.58/24
ip prefix-list ispE_out_deny
    seq 10 permit 9.2.3.4/24
    seq 20 permit 4.4.4.1/24
ip prefix-list ispF_out_deny
    seq 10 permit 2.2.3.4/24
    seq 20 permit 28.2.3.1/24
ip prefix-list ispG_out_deny
    seq 10 permit 4.2.3.4/24
ip prefix-list ispH_in_pref-150
ip prefix-list ispI_out_deny
    seq 10 permit 3.2.3.4/24

私が望むもの:

ip prefix-list ispA_in_pref-150
ip prefix-list ispB_in_pref-100
ip prefix-list ispD_in_pref-50
    seq 10 permit 5.2.3.4/24
ip prefix-list ispD_in_pref-100
    seq 10 permit 4.18.27.58/24
ip prefix-list ispH_in_pref-150

私が得続けるのは次のような出力です(そしてsedコマンド):

:~$ sed -e '/deny/{:a;N;/\n.*seq.*/!ba;d}' file
ip prefix-list ispA_in_pref-150
ip prefix-list ispB_in_pref-100
ip prefix-list ispD_in_pref-50
    seq 10 permit 5.2.3.4/24
ip prefix-list ispD_in_pref-100
    seq 10 permit 4.18.27.58/24
    seq 20 permit 4.4.4.1/24
    seq 20 permit 28.2.3.1/24
ip prefix-list ispH_in_pref-150

まったく異なるリストから2つの異なる「seq 20」行を取得する方法に注意してください。

GPT の場合、次の例が提供されます。

Line 1
Pattern Line
Line 2
This is a line below Line 2
Another line below Line 2
Pattern Line
Line 3

結果は次のとおりです。

:~$ sed -e '/Line 2/{:a;N;/\nPattern.*/!ba;d}' input_file
Line 1
Pattern Line
Line 2
Line 3

私はこれを再現できましたが、ACLファイルを使用しませんでした。

sedにコンテキストを提供するためにバッファを維持することでこれを行う方法があると誓うことができますが、投稿を再配置できないため、実行された他のコマンドがあるかどうかはわかりません。 sedはネットワーク表記の「/」によって混乱を引き起こしますか?もっと良い方法がありますか?

答え1

奇妙な:

$ awk '/deny/ { deny=1; next }
       /^ip/  { deny=0; print; next }
       !deny' < data
ip prefix-list ispA_in_pref-150
ip prefix-list ispB_in_pref-100
ip prefix-list ispD_in_pref-50
    seq 10 permit 5.2.3.4/24
ip prefix-list ispD_in_pref-100
    seq 10 permit 4.18.27.58/24
ip prefix-list ispH_in_pref-150

答え2

awkを使用してください。

$ awk '/^ip/{f=/deny/} !f' file
ip prefix-list ispA_in_pref-150
ip prefix-list ispB_in_pref-100
ip prefix-list ispD_in_pref-50
    seq 10 permit 5.2.3.4/24
ip prefix-list ispD_in_pref-100
    seq 10 permit 4.18.27.58/24
ip prefix-list ispH_in_pref-150

答え3

直面する問題は、シスコのプレフィックスのリストが本質的に階層的であり、正規表現だけではsedかなり複雑になる可能性があるためです。シングルラインパターンのマッチングと交換に適しています。希望の結果を得るにはawkperl以下を使用するソリューションは次のとおりですawk

awk '
  /^ip prefix-list/ {  # If the line starts with "ip prefix-list"
    list_name = $3   # Set list_name to the third field
    match(list_name, /^.*\//)  # Check if list_name contains a slash
    if (RSTART) {  # If it does, it's a main list, print it
      print
      in_main_list = 1
    } else {  # Otherwise, it's a sub-list, ignore it
      in_main_list = 0
    }
  }
  /^ / && in_main_list {  # If the line starts with a space (sub-list) and in_main_list is true
    next  # Skip this line
  }
  in_main_list {  # If we are inside a main list, print the line
    print
  }
' file

スクリプトは次のことを行いますawk

  1. 「ip prefix-list」で始まる行に会ったら、リスト名にスラッシュ( "/")が含まれていることを確認してください。その場合、デフォルトのリストとして扱われ、スクリプトはそれを印刷し、in_main_listフラグ()をtrueに設定します。

  2. 行が空白で始まりin_main_listtrueの場合は、その行をスキップします(サブリスト項目を無視)。

  3. true の場合、in_main_list行を印刷します。

このスクリプトはサブリスト項目をフィルタリングして目的の出力を提供する必要があります。

関連情報