Is there a way to print 2 lines (if any) before and after a target or print a placeholder if not?

2

0

I'm not native english speaker so I hope to be clear.

I know about grep -C 2 "TARGET" inputfile to select 2 rows before and after the row of the TARGET, but I'm not able to use it to manage my problem. I have files structured like this

1 0 value1 value2 value3
2 H value1 value2 value3
3 H value1 value2 value3
4 H value1 value2 value3
5 H value1 value2 value3
6 0 value1 value2 value3
7 0 value1 value2 value3
8 H value1 value2 value3
9 0 value1 value2 value3

with several rows. The required solution would be a file like this

X X X X X
1 0 value1 value2 value3
2 H value1 value2 value3 *
3 H value1 value2 value3 
4 H value1 value2 value3

1 0 value1 value2 value3
2 H value1 value2 value3
3 H value1 value2 value3 *
4 H value1 value2 value3 
5 H value1 value2 value3

... all the other till

6 0 value1 value2 value3
7 0 value1 value2 value3
8 H value1 value2 value3 *
9 0 value1 value2 value3
X X X X X

where the TARGET is "H" , * is to indicate the selected row (but I don't need * in the output file) and X are placeholders to adjust the number of rows before or after the target! I tried also with awk and sed, with no results.

bonimba3

Posted 2014-02-07T13:49:57.197

Reputation: 23

Answers

4

The same approach as Glenn Jackman's, but with a circular buffer instead of rotating the buffer on every input:

awk -v N=2 -v TARGET=" H " -v PLACE="X X X X X" '
  function check(n, s,     i) {
    a[n%NN]=s
    if (n>N&&a[(n-N)%NN]~TARGET) {
      for (i=n+1;i<=n+NN;++i)
        print a[i%NN]
      print ""
    }
  }

  BEGIN{
    NN=2*N+1
    a[0]=PLACE
    for (i=1;i<=N;++i) { getline a[i]; a[i+N]=PLACE }
  }

  { check(NR,$0) }

  END{
    for (i=NR+1;i<=NR+N;++i) check(i,PLACE)
  }'

rici

Posted 2014-02-07T13:49:57.197

Reputation: 3 493

This is also an interesting answer. thank you, now i don't know which one to choose! – bonimba3 – 2014-02-07T17:13:40.353

Change my mind about correct answer. This variant does not take into account that I want printed only the sequences with a target in the middle (position 3). – bonimba3 – 2014-02-10T09:02:23.317

@bonimba3: do you have an input file which prints an undesired sequence? – rici – 2014-02-10T14:39:17.517

Yes. I have thousands of files to process, so I noticed about that problem in some of file I checked. – bonimba3 – 2014-02-10T15:25:17.353

@bonimba3: if you can actually reproduce the error, I'd be interested because I don't see how it could happen. Are you certain that the target string doesn't occur in some other place in the middle line? – rici – 2014-02-10T15:51:50.973

ah, you're right! what a stupid I am... Sorry for the inconvenience! You deserve the right answer again because your code is more concise. And sorry again!!! – bonimba3 – 2014-02-10T16:19:22.450

4

This will get you most of the way there:

awk -v n=2 -v target=" H " '
    BEGIN {
        lines[0]=""
        for (i=1; i<=n; i++) {
            lines[i]="X X X X X"
            getline; lines[n+i]=$0
        }
    }
    function rotate(i) {
        for (i=1; i<=n*2; i++) 
            lines[i-1] = lines[i]
        lines[n*2]=$0
    }
    function check(i) {
        if (lines[n] ~ target) {
            for (i=0; i<=n*2; i++) 
                print lines[i]
            print ""
        }
    }
    { rotate(); check() }
    END {
        for (i=1; i<=n; i++) {
            $0 = "X X X X X"; rotate(); check()
        }
    }
' inputfile

outputs

X X X X X
1 0 value1 value2 value3
2 H value1 value2 value3
3 H value1 value2 value3
4 H value1 value2 value3

1 0 value1 value2 value3
2 H value1 value2 value3
3 H value1 value2 value3
4 H value1 value2 value3
5 H value1 value2 value3

2 H value1 value2 value3
3 H value1 value2 value3
4 H value1 value2 value3
5 H value1 value2 value3
6 0 value1 value2 value3

3 H value1 value2 value3
4 H value1 value2 value3
5 H value1 value2 value3
6 0 value1 value2 value3
7 0 value1 value2 value3

6 0 value1 value2 value3
7 0 value1 value2 value3
8 H value1 value2 value3
9 0 value1 value2 value3
X X X X X

glenn jackman

Posted 2014-02-07T13:49:57.197

Reputation: 18 546

impressive! And, with a bit of study, also very clear. Thank you – bonimba3 – 2014-02-07T17:09:22.210

testing with n=3 didn't work for some reason -- didn't get a block centered on line 8. I'll leave that as an exercise. – glenn jackman – 2014-02-07T18:28:17.970

@glennjackman: i is not local. – rici – 2014-02-10T16:07:12.620