Удалить строки между двумя шаблонами, но только если между ними есть определенная строка

Удалить строки между двумя шаблонами, но только если между ними есть определенная строка

Например, у меня есть файл со следующим содержимым:

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

Связанный контент