Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Search for multiple patterns which included double quotes in single file and comment above and below two lines

Tags:

grep

bash

sed

I have a very large file where I need to search for 40 patterns. If pattern got matched in the file then need to comment before 2 lines and after 2 lines. Patterns will be like as shown below:

1.create_rev -name "2x_8_PLL"
2.create_generated_rev -name "76_L"
3.create_rev -name "PCS_T0"
4.create_generated_rev -name "x544_P"

If I need to search for single pattern then I can execute below gvim command to accomplish the task.

:g/create_rev -name "2x_8_PLL"/-2,+2s/^/#

But the search patterns are more in number 40 plus. How to search/grep for 40+ patterns such that my expected output as shown below:

#pp
#oo
create_rev -name "2x_8_PLL"
#aa
#bb
hh
#ii
#jj
create_generated_rev -name "76_L"
#cc
#dd
create_rev -name "PCS_T0"
#ee
#ff
gg
like image 684
Rama Avatar asked Nov 17 '25 05:11

Rama


2 Answers

This might work for you (GNU grep and sed):

grep -A2 -B2 -nFf targets file |sed -En 's/^([0-9]+)-.*/\1s@^@#@/p' |sed -f - file

Use grep to ouput lines in the file matching the lines in the targets. The matches will be line numbered and contain two lines before and after the matches.

The lines output from the grep command are piped into sed and used as addresses for a sed script, which inserts a # at the start of each matching address.

The sed script created from the ouput of the first sed invocation (by way of the -f command line option and the - which uses stdin from the pipe) is used in the second sed invocation which edits the source file.

Another solution using sed only:

sed -E 's/.*/\\#\\n.*\\n&\\n.*\\n#bb/' targets |
sed -Ee ':a;N;s/\n/&/4;Ta' -f - -e 'bc;:b;s/^([^#])/#\1/mg;s/^#//m3;:c;P;D' file
like image 177
potong Avatar answered Nov 20 '25 03:11

potong


Assuming that when you say "pattern" what you really want is full-line string matching then using any awk in any shell on every Unix box and handling cases of overlapping ranges by commenting them as presumably required and not double-commenting them as could happen with other solutions:

$ cat tst.awk
ARGIND==1 {
    targets[$0]
    next
}
ARGIND==2 {
    if ($0 in targets) {
        for (i=FNR-2; i<=FNR+2; i++) {
            if (i != FNR) {
                hits[i]
            }
        }
    }
    next
}
FNR in hits {
    $0 = "#" $0
}
{ print }

$ awk -f tst.awk targets file file
#pp
#oo
create_rev -name "2x_8_PLL"
#aa
#bb
hh
#ii
#jj
create_generated_rev -name "76_L"
#cc
#dd
create_rev -name "PCS_T0"
#ee
#ff
gg

$ cat targets
create_rev -name "2x_8_PLL"
create_generated_rev -name "76_L"
create_rev -name "PCS_T0"
create_generated_rev -name "x544_P"

The above uses GNU awk for ARGIND. If you don't have GNU awk then change ARGIND==1 to FILENAME==ARGV[1] and ARGIND==2 to FILENAME==ARGV[2].

like image 33
Ed Morton Avatar answered Nov 20 '25 03:11

Ed Morton