Elimina líneas entre 2 patrones, pero solo si tiene una cadena específica entre ellos

Elimina líneas entre 2 patrones, pero solo si tiene una cadena específica entre ellos

Ejemplo, tengo un archivo con el siguiente contenido:

eggs
bacon
cereal

eggs
bacon
cheese
cereal

Producción:

eggs
bacon
cereal

En el ejemplo, quiero eliminar líneas entre las palabras eggsy cereal, pero solo si contiene cheesealgo intermedio.

¿Cómo podría hacer esto usando sed?

Me pidieron que fuera más específico, así que esto es básicamente lo que quiero hacer, y espero que esto quede más claro:

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

Este es el comando que probé:

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

Ese comando simplemente elimina desde el primero "crosshair"hasta el último }, independientemente de si tiene la línea "sprites/crosshairs"intermedia o no.

Solo quiero eliminar de "crosshair"a }si entre los patrones "sprites/crosshairs"se encuentra la cadena. Sin embargo, hay otros bloques de código en el archivo de texto que contiene "sprites/crosshairs".

Como:

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

Esto no se puede eliminar. Pido disculpas PROFUNDAMENTE por no haber explicado esto antes, pero no pensé que fuera necesario.

La sugerencia de don_crissti funciona bastante bien, lo cual essed '/crosshair/,/\}/{H;/\}/!d;s/.*//;x;/sprites\/crosshairs/d;s/.//;}' infile

Sin embargo, el resultado es este:

              ...
              "autoaim"
              {
  }
}

"autoaim"se eliminó parcialmente, pero no por completo, pero como puede ver, el bloque que contiene "sprites/crosshairs"se eliminó, como quería hacer, pero autoaimaún no se puede modificar.

Respuesta1

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

Cómo funciona:

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

Esto supone que las líneas coincidentes ^[[:blank:]]*"crosshair"siempre van seguidas de un bloque de líneas entre llaves, como en su ejemplo.

Respuesta2

si perlestá bien, se puede usar el modo de párrafo ( -00opción) y usar la coincidencia de expresiones regulares de varias líneas

$ cat ip.txt 
eggs
bacon
cereal

eggs
bacon
cheese
cereal

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

información relacionada