sed for appending a line before a pattern and after another patter.

Hi All,

I'm appending a line before a pattern and after another pattern(:wink: but omitting the first pattern - same as if comes duplicates before the second pattern.

Also, I'm adding a word before the first pattern -

Here is my file


select blah blah
hello
select blah blah
;

select blah blah
hi
select blah blah
;

My expectation would be -

\o | grep org
anyword select blah blah
hello
select blah blah
;
\o

\o | grep org
anyword select blah blah
hi
select blah blah
;
\o

Here is my sed command I'm using with my file-

sed -e '/^ *[sS][eE][lL][eE][cC][tT]/ i \\\o | grep org' testfilepr.txt | sed -e 's/\(^ *[sS][eE][lL][eE][cC][tT]\)/anyword \1/g' | sed -e ' s/;/;\n\\\o/'

But my output comes out to be -

\o | grep org
anyword select blah blah
hello
\o | grep org
anyword select blah blah
;
\o

\o | grep org
anyword select blah blah
hi
\o | grep org
anyword select blah blah
;
\o

Please suggest.

A sed multi-liner

sed '/^ *[sS][eE][lL][eE][cC][tT]/{
  i\
\\o grep org
  s/^ */anyword /
  :L
  $!N
  /;/!bL
  a\
\\o
}
'

The loop appends the following lines until the end marker ; so there are no further insertions.

1 Like

Thanks MadeInGermany!! Your code is working for me in mentioned scenarios.

Could you please help out if we have some data like -

(
select blah blah
hello
select blah blah
;

select blah blah
hi
select blah blah
;

or

(select blah blah
hello
select blah blah
;

select blah blah
hi
select blah blah
;

In such cases, expectation would be -

\o | grep org
(
anyword select blah blah
hello
select blah blah
;
\o

\o | grep org
anyword select blah blah
hi
select blah blah
;
\o

or

\o | grep org
(anyword select blah blah
hello
select blah blah
;
\o

\o | grep org
anyword select blah blah
hi
select blah blah
;
\o

This one tolerates one or more ( on two lines before the select

sed '
/^ *(/N
/^\( *(* *\n* *(* *\)\([sS][eE][lL][eE][cC][tT]\)/{
  s//\\o | grep org\
\1anyword \2/
  :L
  $!N
  /;/!bL
  a\
\\o
}
'

I am using the s (substitute) command for both insertions, because it can use the \( \) back references in the previous / / .

If I'm using below pattern, it will error out.

sed '
/^ *(/N
/^\( *(* *\n* *(* *\)\([sS][eE][lL][eE][cC][tT]\)/{
s//\\\o | grep \x27Send\\|Recv\\|Execute on\x27 | sed -e \x27s/^[ \\t]*//g\x27 -e \x27s/[|]*//g\x27  -e \x27s/[ \\t]*//g\x27 | cut -d\x27"\x27 -f2 | cut -d: -f1,2 | cut -d\\\\ -f1,2\
\1explain \2/
:L
$!N
/;/!bL
a\
\\o
}' filename.txt

The sed uses s /search/replace/ i.e. / delimiters, so there may not be a / in the search and replace strings.
Use another delimiter, e.g. # :

sed '
/^ *(/N
/^\( *(* *\n* *(* *\)\([sS][eE][lL][eE][cC][tT]\)/{
  s##\\o | grep org\
\1anyword \2#
  :L
  $!N
  /;/!bL
  a\
\\o
}
' filename.txt
 

If required, this is also possible for the /search/ , but the start delimiter needs to be escaped:

sed '
 \#^ *(#N
 \#^\( *(* *\n* *(* *\)\([sS][eE][lL][eE][cC][tT]\)#{
 ...
  

This is a a "sed" thread, but for comparison sake, if there are always empty lines between pattern groups then an awk version could look like this:

awk '
  tolower($0)~/^\(?\n?select/ && $NF==";" {
    $0="\\o | grep org\n" $0 "\n\\o"
  }
  print
'  RS= ORS='\n\n' file

--