2

Example, I have a file with the following contents:

eggs
bacon
cereal

eggs
bacon
cheese
cereal

Output:

eggs
bacon
cereal

In the example, I want to delete lines between the words eggs and cereal, but only if it contains cheese in between.

How could I do this using sed?

I have been asked to be more specific, so here is basically what I want to do, and I hope this makes it more clear:

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

This is the command I tried:

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

That command just deletes from the very first "crosshair" to the very last }, regardless of whether it has the line "sprites/crosshairs" inbetween or not.

I only want to delete from "crosshair" to } if between the patterns, the string "sprites/crosshairs" is found. However there are other blocks of code on the text file containing "sprites/crosshairs".

Such as:

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

This cannot be removed. I DEEPLY apologize for not explaining this earlier, but I did not think it would be necessary.

don_crissti's suggestion works quite well which is sed '/crosshair/,/\}/{H;/\}/!d;s/.*//;x;/sprites\/crosshairs/d;s/.//;}' infile

The output is this, however:

              ...
              "autoaim"
              {
  }
}

"autoaim" is partially deleted, but not completely, but as you can see the block containing "sprites/crosshairs" is removed, as I wanted to do, but autoaim still cannot be modified

  • So what have you tried so far? – Joseph R. Sep 28 '16 at 3:43
2
sed '/^[[:blank:]]*"crosshair"/,/}/{H;/}/!d;s/.*//;x;/sprites\/crosshairs/d;s/.//;}' infile

How it works:

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

This assumes lines matching ^[[:blank:]]*"crosshair" are always followed by a block of lines enclosed in braces, just like in your example.

  • Thank you. Your answer has gotten me the closest to the desired result, but there is still one last problem. The question has been edited for one last time. – Septue Sep 28 '16 at 14:24
  • It has been done. – Septue Sep 28 '16 at 14:38
  • The output is the same, with autoaim being partially deleted, but, I am new to this site, and your dedication to answering my question is amazing. Thank you so very much. – Septue Sep 28 '16 at 15:08
  • This did the job. Thank you again for your patience! – Septue Sep 28 '16 at 18:03
1

if perl is okay, one can use paragraph mode (-00 option) and use multi-line regex match

$ cat ip.txt 
eggs
bacon
cereal

eggs
bacon
cheese
cereal

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.