2つのパターンの間にある行を削除しますが、間に特定の文字列がある場合のみ削除します。

2つのパターンの間にある行を削除しますが、間に特定の文字列がある場合のみ削除します。

たとえば、次の内容のファイルがあります。

eggs
bacon
cereal

eggs
bacon
cheese
cereal

出力:

eggs
bacon
cereal

eggsこの例では、と という単語の間の行を削除したいのですcerealが、cheese間に が含まれている場合のみです。

を使ってこれをどうやったらできるでしょうかsed

もっと具体的に説明するよう求められたので、基本的に私がやりたいことは次のとおりです。これでより明確になると思います。

WeaponData
{
    TextureData
    {
                "crosshair"
                {
                                "file"  "vgui/replay/thumbnails/"
                                "x"             "0"
                                "y"             "0"
                                "width"         "64"
                                "height"        "64"
                }
                "weapon"
                {
                                "file"          "sprites/bucket_bat_red"
                                "x"             "0"
                                "y"             "0"
                                "width"         "200"
                                "height"                "128"
                }
                "weapon_s"
                {       
                                "file"          "sprites/bucket_bat_blue"
                                "x"             "0"
                                "y"             "0"
                                "width"         "200"
                                "height"                "128"
                }

                "ammo"
                {
                                "file"          "sprites/a_icons1"
                                "x"             "55"
                                "height"    "15"
                }

                "crosshair"
                {
                    "file"      "sprites/crosshairs" <---
                    "x"     "32"
                    "y"     "32"
                    "width"     "32"
                    "height"    "32"
                }

                "autoaim"
                {
                    "file"      "sprites/crosshairs"
                    "x"     "0"
                    "y"     "48"
                    "width"     "24"
                    "height"    "24"
                }
    }
}

私が試したコマンドは次のとおりです:

sed '/"crosshair"/,/}/d' file.txt

このコマンドは、間に線があるかどうかに関係なく、最初から"crosshair"最後までを削除します。}"sprites/crosshairs"

パターンの間に文字列が見つかった場合のみ、 から を削除したいのですが、"crosshair"テキストファイルには を含む他のコード ブロックがあります。}"sprites/crosshairs""sprites/crosshairs"

のような:

"autoaim"
{
        "file"      "sprites/crosshairs"
        "x"     "0"
        "y"     "48"
        "width"     "24"
        "height"    "24"
}

これは削除できません。以前に説明しなかったことを深くお詫びしますが、その必要はないと考えました。

don_crisstiの提案は非常にうまく機能し、sed '/crosshair/,/\}/{H;/\}/!d;s/.*//;x;/sprites\/crosshairs/d;s/.//;}' infile

ただし、出力は次のようになります。

              ...
              "autoaim"
              {
  }
}

"autoaim"部分的に削除されましたが、完全には削除されていません。しかし、ご覧のとおり、ブロックは"sprites/crosshairs"削除されました。私が望んでいたとおりですが、autoaimまだ変更できません。

答え1

sed '/^[[:blank:]]*"crosshair"/,/}/{H;/}/!d;s/.*//;x;/sprites\/crosshairs/d;s/.//;}' infile

使い方:

sed '/^[[:blank:]]*"crosshair"/,/}/{         # in this range
H                                            # append each line to hold buffer
/}/!d                                        # delete it if not the end of range
s/.*//                                       # empty the pattern space
x                                            # exchanges buffers
/sprites\/crosshairs/d                       # delete pattern space if it matches
s/.//                                        # remove leading newline, autoprint
}' infile

これは、一致する行^[[:blank:]]*"crosshair"の後に、例のように、常に中括弧で囲まれた行のブロックが続くことを前提としています。

答え2

問題がなければperl、段落モード(-00オプション)を使用して、複数行の正規表現マッチを使用することができます。

$ cat ip.txt 
eggs
bacon
cereal

eggs
bacon
cheese
cereal

$ perl -00 -ne 'print if !/^eggs.*cheese.*cereal$/ms' ip.txt 
eggs
bacon
cereal

関連情報