Sokogen
Sokogen

Reputation: 28

BASH. Parsing blocks of text with additional conditions

I have a task to upgrade nagios from version 2 to 4. There are several hundred files with deprecated tags. Here's one of them:

define host {
        use h-common1
        host_name a0
        address XX.XX.XX.XX
        check_command check-host-alive
        parents fw_ext
        }
define hostextinfo {
        host_name a0
        icon_image serv.jpg
        statusmap_image serv.jpg
       }
define service {
        use s-common1
        host_name a0
        service_description check_load
        check_command check_nrpe! check_load
        }

define service {
        use s-common1
        host_name a0
        service_description check-disks
        check_command check_nrpe! check_disk
        }
define service {
        use s-common1
        host_name a0
        service_description check_crond
        check_command check_nrpe! check_procs
        }
define service {
        use s-common1
        host_name a0
        service_description check_ntpd
        check_command check_nrpe! check_procs_1
        }
define service {
        use s-common1
        host_name a0
        max_check_attempts 1
        notification_options c, w
        service_description Find errors in logs
        check_command check_nrpe! check_logct
        }

How do I delete all the rows with the tag "host_name", except that which is in the block "define host"? For example, i use this construction to delete all blocks "define hostextinfo":

for i in * ; do cat $i | sed -e '/}/r exceptions' -e '/^define hostextinfo{/,/}/d' > $i.tmp ; cat $i.tmp > $i; rm $i.tmp ;done

How can i modify this code for my case? I would be glad if I find the solution in one line.

Upvotes: 0

Views: 793

Answers (4)

karakfa
karakfa

Reputation: 67467

yet another awk

 awk '             /define/{del=1}  
       /define host/ || /}/{del=0} 
        /host_name/ && del {next} 1' recs

Upvotes: 0

Ed Morton
Ed Morton

Reputation: 203284

sed is for simple substitutions on individual lines, that is all. All of it's constructs except s, g, and p (with -n) became obsolete in the mid-1970s when awk was invented, people just use them today for the mental exercise, not to actually create scripts they would use.

You didn't post your expected output so we're all guessing but is this what you want?

$ awk '$1=="define"{type=$2} !($1=="host_name" && type!="host")' file
define host {
        use h-common1
        host_name a0
        address XX.XX.XX.XX
        check_command check-host-alive
        parents fw_ext
        }
define hostextinfo {
        icon_image serv.jpg
        statusmap_image serv.jpg
       }
define service {
        use s-common1
        service_description check_load
        check_command check_nrpe! check_load
        }

define service {
        use s-common1
        service_description check-disks
        check_command check_nrpe! check_disk
        }
define service {
        use s-common1
        service_description check_crond
        check_command check_nrpe! check_procs
        }
define service {
        use s-common1
        service_description check_ntpd
        check_command check_nrpe! check_procs_1
        }
define service {
        use s-common1
        max_check_attempts 1
        notification_options c, w
        service_description Find errors in logs
        check_command check_nrpe! check_logct
        }

Normally I'd advise against a double negative but in this case I find the above easier to understand than the alternative if you remove the double negative:

awk '$1=="define"{type=$2} $1!="host_name" || type=="host"' file

Upvotes: 1

cadrian
cadrian

Reputation: 7376

With awk maybe?

/^define host / {print; h=1; next}
/^define/       {print; h=0; next}
/host_name/     {if (h) print; next}
                {print}

Upvotes: 4

Kent
Kent

Reputation: 195039

give this line a try:

awk '/^define host /{k=1}/[}]/{k=0}!k&&/host_name/{next}7' file

Upvotes: 4

Related Questions