0

I tried to come up with a Tcl script, but I'm looking for something in sed/awk commands to make this faster.

The file contains the following:

*Other text*
.....
.....
.....
SECTION LABELS {
lab M1 0 0 0 0 3 1 bot
lab M2 0 0 0 0 3 1 top
} SECTION LABELS

*Other text*
......
......
......
SECTION LABELS {
lab M1:NET 5207 12261 5207 12261 0 2 A
lab M2:NET 6880 5370 6880 5370 0 2 B
lab M1:NET 3454 5386 3454 5386 0 2 alpha
lab M2:NET 3454 5386 3454 5386 0 2 beta
} SECTION LABELS

I'm interested only in the lines containing within "SECTION LABELS". I'd like to:

  • Change M1:NET to M1 and M2:NET to M2
  • If the last element is A or B, change the number before A or B from 2 to 3
  • If the last element is anything else, change the number (last but one) from 2 to 6
  • If the numbers after lab M1:NET or lab M1 are 0 0 0 0, then I do not want to change anything.
  • Rest of the contents of the file remain the same

So the output looks like:

*Other text*
.....
.....
.....
SECTION LABELS {
lab M1 0 0 0 0 3 1 bot
lab M2 0 0 0 0 3 1 top
} SECTION LABELS

*Other text*
......
......
......
SECTION LABELS {
lab M1 5207 12261 5207 12261 0 3 A
lab M2 6880 5370 6880 5370 0 3 B
lab M1 3454 5386 3454 5386 0 6 alpha
lab M2 3454 5386 3454 5386 0 6 beta
} SECTION LABELS
Jordan Running
  • 102,619
  • 17
  • 182
  • 182
user741196
  • 49
  • 8

2 Answers2

2

Here is some to get you started:

awk '/SECTION LABELS/ {f=!f} f && /NET/ && !/lab M1(:NET)* 0 0 0 0/ {split($2,a,":");$2=a[1];if ($NF~/\<[A|B]\>/) $(NF-1)=3; else $(NF-1)=6}1' t
*Other text*
.....
.....
.....
SECTION LABELS {
lab M1 0 0 0 0 3 1 bot
lab M2 0 0 0 0 3 1 top
} SECTION LABELS

*Other text*
......
......
......
SECTION LABELS {
lab M1 5207 12261 5207 12261 0 3 A
lab M2 6880 5370 6880 5370 0 3 B
lab M1 3454 5386 3454 5386 0 6 alpha
lab M2 3454 5386 3454 5386 0 6 beta
} SECTION LABELS
Jotne
  • 40,548
  • 12
  • 51
  • 55
  • it works if the last word is a single character like A or B. Say if the last letter is AA or BB, the script doesn't work. Any work around for that? Even when I change this condition as if ($NF~/\<[AA|BB]\>/ – user741196 Sep 03 '14 at 18:06
  • 1
    @user741196 you can use `($NF~/\<(AA|BB)\>/)` or `($NF=="AA" || $NF=="BB")` – Jotne Sep 03 '14 at 19:29
  • This one doesn't replace M1:NET to M1 though.. but I got the solution. Thanks much! Appreciate it – user741196 Sep 03 '14 at 21:17
  • 1
    @user741196 Fixed the `NET` change. My first post did have it, but since you changed your post some couple of times, it was lost in the process. – Jotne Sep 04 '14 at 05:04
2

You can use the range as the pattern and then do operation on texts in between (inclusive). for your input:

awk '/^SECTION LABELS {/,/} SECTION LABELS/{
    sub(":NET","")
    if ($8 && !/M1 0 0 0 0/) $8 = ($NF ~ /^[AB]$/) ? 3 : 6 
}1' file.txt

Note: (1) you will need to adjust the 'if' section if there are more than 7 words in 'SECTION LABELS' (I supposed this is just a sample). you can change '$8' to '$9' or $9 != "" etc to skip the header and trailer.

(2) If A, B are string instead of chars, you will need to change the regex from ^[AB]$ to ^(A|B)$

(3) If you also want to keep M2 0 0 0 0 as is, then change !/M1 0 0 0 0/ to !/\<0 0 0 0\>/ where '\<' and '\>' are word boundaries in regex.

lihao
  • 583
  • 3
  • 6