Löschen Sie Zeilen zwischen zwei Mustern, aber nur, wenn dazwischen eine bestimmte Zeichenfolge steht

Löschen Sie Zeilen zwischen zwei Mustern, aber nur, wenn dazwischen eine bestimmte Zeichenfolge steht

Beispiel: Ich habe eine Datei mit folgendem Inhalt:

eggs
bacon
cereal

eggs
bacon
cheese
cereal

Ausgabe:

eggs
bacon
cereal

Im Beispiel möchte ich Zeilen zwischen den Wörtern eggsund löschen cereal, aber nur, wenn cheesedazwischen steht.

Wie könnte ich dies mithilfe von tun sed?

Ich wurde gebeten, genauer zu werden. Hier ist also im Wesentlichen, was ich tun möchte, und ich hoffe, dies macht es klarer:

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"
                }
    }
}

Dies ist der Befehl, den ich ausprobiert habe:

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

Dieser Befehl löscht nur vom allerersten "crosshair"bis zum allerletzten }, unabhängig davon, ob eine Zeile "sprites/crosshairs"dazwischen steht oder nicht.

"crosshair"Ich möchte nur von bis löschen }, wenn zwischen den Mustern die Zeichenfolge "sprites/crosshairs"gefunden wird. Es gibt jedoch andere Codeblöcke in der Textdatei, die enthalten "sprites/crosshairs".

Wie zum Beispiel:

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

Dies kann nicht entfernt werden. Ich entschuldige mich zutiefst dafür, dass ich dies nicht früher erklärt habe, aber ich dachte nicht, dass es notwendig wäre.

don_crissti's Vorschlag funktioniert ganz gut, das istsed '/crosshair/,/\}/{H;/\}/!d;s/.*//;x;/sprites\/crosshairs/d;s/.//;}' infile

Die Ausgabe ist jedoch diese:

              ...
              "autoaim"
              {
  }
}

"autoaim"ist teilweise gelöscht, aber nicht vollständig, aber wie Sie sehen, "sprites/crosshairs"ist der Block, der enthält, wie ich es wollte, entfernt, kann aber autoaimimmer noch nicht geändert werden

Antwort1

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

Wie es funktioniert:

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

Dies setzt voraus, dass auf übereinstimmende Zeilen ^[[:blank:]]*"crosshair"immer ein Block von Zeilen in Klammern folgt, genau wie in Ihrem Beispiel.

Antwort2

wenn perldas ok ist, kann man den Absatzmodus ( -00Option) verwenden und mehrzeilige Regex-Übereinstimmung verwenden

$ cat ip.txt 
eggs
bacon
cereal

eggs
bacon
cheese
cereal

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

verwandte Informationen