SED:パターンマッチング後5行上、下4行削除

SED:パターンマッチング後5行上、下4行削除

以下の詳細を含むヒューファイルがあります。

define host{
        use                     generic-host            ; Name of host template to use
        host_name               ServerA_172.29.16.102
        alias                   ServerA_172.29.16.102
        address                 172.29.16.102
        check_command           check-host-alive
        max_check_attempts      3
        notification_interval   120
        notification_period     24x7
        }



define host{
        use                     generic-host            ; Name of host template to use
        host_name               ServerB_172.29.16.103
        alias                   ServerB_172.29.16.103
        address                 172.29.16.103
        check_command           check-host-alive
        max_check_attempts      3
        notification_interval   120
        notification_period     24x7
        }

私が望むのは、"address 172.29.16.102"5行上、4行後の4行を見つけて削除することです。

sedを試しましたが、うまくいきません

sed '$N;$N;N;/address                 172.29.16.102/,+5d' hosts

答え1

これは、各define_host部分が1つ以上の改行で区切られている場合、GNU awkで発生する問題の種類とまったく同じです。複数行のレコードサポートは解決のためである

awk -v RS= '!/172.29.16.102/{printf $0""RT}'

答え2

このような質問を見ると直感的にこれが職業だと思いますgrep。ただし、前方および後方のスイッチ(&)を使用するときに結果を反転()する機能はgrepこれを許可しません。-v-B ..-A ..

grepしかし、これを2回呼び出すこの賢いアプローチは、これまでに見たソリューションよりawkはるかにきれいです。sed

$ grep -v "$(grep -B 4 -A 5 'address 172.29.16.102' <file>)" <file>

はい

以下は、いくつかのサンプルデータです。

$ cat sample.txt
define host{
        use                     generic-host            ; Name of host template to use
        host_name               ServerA_172.29.16.102
        alias                   ServerA_172.29.16.102
        address                 172.29.16.102
        check_command           check-host-alive
        max_check_attempts      3
        notification_interval   120
        notification_period     24x7
        }

line1b
line2b
line3b
line4b
address 172.29.16.102
line5a
line4a
line3a
line2a
line1a

define host{
        use                     generic-host            ; Name of host template to use
        host_name               ServerB_172.29.16.103
        alias                   ServerB_172.29.16.103
        address                 172.29.16.103
        check_command           check-host-alive
        max_check_attempts      3
        notification_interval   120
        notification_period     24x7
        }

次のコマンドを実行すると、

$ grep -v "$(grep -B 4 -A 5 'address 172.29.16.102' sample.txt)" sample.txt
define host{
        use                     generic-host            ; Name of host template to use
        host_name               ServerA_172.29.16.102
        alias                   ServerA_172.29.16.102
        address                 172.29.16.102
        check_command           check-host-alive
        max_check_attempts      3
        notification_interval   120
        notification_period     24x7
        }


define host{
        use                     generic-host            ; Name of host template to use
        host_name               ServerB_172.29.16.103
        alias                   ServerB_172.29.16.103
        address                 172.29.16.103
        check_command           check-host-alive
        max_check_attempts      3
        notification_interval   120
        notification_period     24x7
        }

答え3

sed理由の完璧な例は次のとおりです。Sトレメ編集するexitorであり、内部ファイル編集機能を決して置き換えません。

ex -c '/address  *172.29.16.103/
?{?,/}/d
x' input

このコマンドは単純化された形式であり、強力ではありませんが、説明のために使用されます。

最初のコマンドは指定された正規表現を探し、カーソルをその行に移動します。

2番目のコマンドは、deleteコマンドが実行される2つのカンマ区切りアドレスで構成されています。 ?{?現在の行で後方に開く中括弧を検索し、/}/現在の行で前方に閉じている中かっこを検索します。その間のすべての内容が削除されます(1行ずつ、開いた中括弧行の先頭も削除されます)。

x変更を保存して終了します。もちろんinputファイル名です。

このコマンドは、入力した入力に対して期待どおりに正しく機能します。


今、私はこれが大幅に改善できると述べました。正規表現から始めます。ここで最も顕著な特徴は、ピリオドがワイルドカード文字であることです。与えられた正規表現は「172329-16 103」とも一致できます。したがって、ピリオドはリテラルピリオドとのみ一致するようにバックスラッシュでエスケープする必要があります。

以下は空白です。 2つのスペースの後に*があります(使用できますが、\+POSIXにその機能が必要かどうかは不明です)。ファイルにタブがあるとどうなりますか?最良の解決策はを使用することです[[:space:]]。 (これは良く見えます\+。これがPOSIXであるかどうかを調べた人がいる場合は、コメントを残してください。)

最後に、正規表現が次のような場合いいえファイルで見つかりましたか?これにより、ファイルが編集用に開かれ、「検索」コマンドが失敗し、エラーメッセージが表示され、指定されたコマンドの残りの部分は実行されません。エディタに残って検索できますex。手動で変更されます。ただし、スクリプトの編集を自動化するにはエディタが必要な場合があります。出口変更が必要ない場合。答えはgグローバルコマンドを使用し、この-sフラグを使用してすべての出力を抑制することですex

ex -sc 'g/address[[:space:]][[:space:]]*172\.29\.16\.103/ ?{?,/}/d
x' input

これはないかなり前のコマンドと同じです。一致する行がある中括弧ブロックが複数ある場合、ここのグローバルコマンドはそのブロックをすべて削除します。とにかく、これはおそらくあなたが望むものです。

最初の一致のみを削除し、一致がまったくない場合にファイルを変更せずに終了するには、このコマンドをコマンド引数xの一部として使用しg(最初の削除コマンドを実行してファイルを終了し)、次のq!場所にコマンドを追加します。g一致する行がないため、コマンドが実行されない場合に備えて下部に表示されます。

ex -sc 'g/address[[:space:]][[:space:]]*172\.29\.16\.103/ ?{?,/}/d | x
q!' input

正直なところ、これらのコマンドはプロセスを実際よりもはるかに複雑に見せます。堅牢性は、コードの極端な明確性と可読性を犠牲にして発生します。これは妥協案です。

ex感じを得るには、一部のファイルを対話形式で編集することをお勧めします。だからあなたはできますバラより何をしてください。この修正を対話的に実行する編集セッションはex次のとおりです。

$ ex input
"input" 23L, 843C
Entering Ex mode.  Type "visual" to go to Normal mode.
:/103
        host_name               ServerB_172.29.16.103
:?{?,/}/d                             # This deletes the current block

:$p                                   # Print and move to last line

:-5,.p                                # Print some more lines to check result
        notification_interval   120
        notification_period     24x7
        }



:?}?+,.d                              # Trim whitespace
        }
:x                                    # Save and exit
$ 

これPOSIX仕様ex追加資料が提供されます。

答え4

これはどうですか?

egrep -v '^([[:space:]]+(use|host_name|alias|check_command|max_check_attempts|notification_interval|notification_period)[[:space:]]+|^define host{|^[[:space:]]+})'

ファイルに同様の行がないと仮定すると、不要な特定の行を削除します。

関連情報