Apagar linhas entre 2 padrões, mas somente se tiver uma string específica entre

2

Exemplo, eu tenho um arquivo com o seguinte conteúdo:

eggs
bacon
cereal

eggs
bacon
cheese
cereal

Saída:

eggs
bacon
cereal

No exemplo, desejo excluir linhas entre as palavras eggs e cereal , mas somente se ela contiver cheese entre elas.

Como eu poderia fazer isso usando sed ?

Pediram para ser mais específico, então aqui está basicamente o que eu quero fazer, e espero que isso torne isso mais 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 é o comando que tentei:

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

Esse comando apenas exclui do primeiro "crosshair" para o último } , independentemente de ter a linha "sprites/crosshairs" entre ou não.

Eu só quero excluir de "crosshair" to } se entre os padrões, a string "sprites/crosshairs" for encontrada. No entanto, existem outros blocos de código no arquivo de texto contendo "sprites/crosshairs" .

Como:

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

Isso não pode ser removido. Eu peço desculpas por não ter explicado isso antes, mas não achei que fosse necessário.

A sugestão de don_crissti funciona muito bem, o que é sed '/crosshair/,/\}/{H;/\}/!d;s/.*//;x;/sprites\/crosshairs/d;s/.//;}' infile

A saída é esta, no entanto:

              ...
              "autoaim"
              {
  }
}

"autoaim" foi parcialmente excluído, mas não completamente, mas como você pode ver, o bloco contendo "sprites/crosshairs" foi removido, como eu queria, mas autoaim ainda não pode ser modificado

    
por Septue 28.09.2016 / 05:01

2 respostas

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

Como 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

Isso pressupõe que as linhas correspondentes a ^[[:blank:]]*"crosshair" sejam sempre seguidas por um bloco de linhas entre chaves, assim como no seu exemplo.

    
por 28.09.2016 / 16:17
1

se perl estiver ok, pode-se usar o modo de parágrafo ( -00 opção) e usar correspondência de regex de várias linhas

$ cat ip.txt 
eggs
bacon
cereal

eggs
bacon
cheese
cereal

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