How to inplace substitute the content between 2 tags with SED (bash)?

Viewed 70

I want to inplace edit a file with sed (Oracle-Linux/Bash).

The content between 2 search-tags (in form of "#"-comments) should get commented out.

Example:

Some_Values
#NORMAL_LISTENER_START
LISTENER =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = IPC)
         (KEY      = LISTENER)
    )
  )
)
#NORMAL_LISTENER_END
Other_Values

Should result in:

Some_Values    
#NORMAL_LISTENER_START
# LISTENER =
#   (DESCRIPTION =
#     (ADDRESS = (PROTOCOL = IPC)
#          (KEY      = LISTENER)
#     )
#   )
# )
#NORMAL_LISTENER_END
Other_Values

The following command already achieves it, but it also puts a comment+blank in front of the search-tags:

sed -i "/#NORMAL_LISTENER_START/,/#NORMAL_LISTENER_END/ s/^/# /" ${my_file}

Now my research told me to exclude those search-tags like:

sed -i '/#NORMAL_LISTENER_START/,/#NORMAL_LISTENER_END/{//!p;} s/^/# /' ${my_file}

But it won't work - with the following message as a result:

sed: -e expression #1, char 56: extra characters after command

I need those SearchTags to be as they are, because I need them afterwards again.

3 Answers

If ed is available/acceptable.

printf '%s\n' 'g/#NORMAL_LISTENER_START/+1;/#NORMAL_LISTENER_END/-1s/^/#/' ,p Q | ed -s file.txt
  • Change Q to w if you're satisfied with the output and in-place editing will occur.

  • Remove the ,p If you don't want to see the output.

This might work for you (GNU sed):

sed '/#NORMAL_LISTENER_START/,/#NORMAL_LISTENER_END/{//!s/^/# /}' file

Use a range, delimited by two regexp and insert # before the lines between the regexps but not including the regexps.

Alternative:

sed '/#NORMAL_LISTENER_START/,/#NORMAL_LISTENER_END/{s/^[^#]/# &/}' file

Or if you prefer:

sed '/#NORMAL_LISTENER_START/{:a;n;/#NORMAL_LISTENER_END/!s/^/# /;ta}' file

With your shown samples only, please try following awk code. Simple explanation would be, look for specific string and set/unset vars as per that and then print updated(added # in lines) lines as per that, stop updating lines once we find line from which we need not to update lines.

awk ' /Other_Values/{found=""} found{$0=$0!~/^#/?"#"$0:$0} /Some_Values/{found=1} 1' Input_file

Above will print output on terminal, once you are happy with results you could run following code to do inplace save into Input_file.

awk ' /Other_Values/{found=""} found{$0=$0!~/^#/?"#"$0:$0} /Some_Values/{found=1} 1' Input_file > temp && mv temp Input_file

Explanation: Adding detailed explanation for above.

awk '                                    ##Starting awk program from here.
/Other_Values/{ found=""             }   ##If line contains Other_Values then nullify found here.  
found        {  $0=$0!~/^#/?"#"$0:$0 }   ##If found is SET then check if line already has # then leave it as it is OR add # in starting to it.
/Some_Values/{ found=1               }   ##If line contains Some_Values then set found here.
1                                        ##Printing current line here.
' Input_file                             ##Mentioning Input_file name here.
Related