Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replace text between two strings in file using linux bash

Tags:

linux

bash

sed

i have file "acl.txt"

 192.168.0.1
 192.168.4.5
 #start_exceptions
 192.168.3.34
 192.168.6.78
 #end_exceptions
 192.168.5.55

and another file "exceptions"

 192.168.88.88
 192.168.76.6

I need to replace everything between #start_exceptions and #end_exceptions with content of exceptions file. I have tried many solutions from this forum but none of them works.

like image 376
Kriss Avatar asked Feb 19 '14 09:02

Kriss


People also ask

How do I replace text in a file in bash?

To replace content in a file, you must search for the particular file string. The 'sed' command is used to replace any string in a file using a bash script. This command can be used in various ways to replace the content of a file in bash. The 'awk' command can also be used to replace the string in a file.

How do I replace a string with another string in Linux?

Use Stream EDitor (sed) as follows: sed -i 's/old-text/new-text/g' input.txt. The s is the substitute command of sed for find and replace. It tells sed to find all occurrences of 'old-text' and replace with 'new-text' in a file named input.txt.

How do I replace text in a file?

Replacing text within NotepadOpen the text file in Notepad. Click Edit on the menu bar, then select Replace in the Edit menu. Once in the Search and Replace window, enter the text you want to find and the text you want to use as a replacement.


2 Answers

EDITED:

Ok, if you want to retain the #start and #stop, I will revert to awk:

awk '
    BEGIN       {p=1}
    /^#start/   {print;system("cat exceptions");p=0}
    /^#end/     {p=1}
    p' acl.txt

Thanks to @fedorqui for tweaks in comments below.

Output:

192.168.0.1
192.168.4.5
#start_exceptions
192.168.88.88
192.168.76.6
#end_exceptions
192.168.5.55

p is a flag that says whether or not to print lines. It starts at the beginning as 1, so all lines are printed till I find a line starting with #start. Then I cat the contents of the exceptions file and stop printing lines till I find a line starting with #end, at which point I set the p flag back to 1 so remaining lines get printed.

If you want output to a file, add "> newfile" to the very end of the command like this:

awk '
    BEGIN       {p=1}
    /^#start/   {print;system("cat exceptions");p=0}
    /^#end/     {p=1}
    p' acl.txt > newfile

YET ANOTHER VERSION IF YOU REALLY WANT TO USE SED

If you really, really want to do it with sed, you can use nested address spaces, firstly to select the lines between #start_exceptions and #end_exceptions, then again to select the first line within that and also lines other than the #end_exceptions line:

sed '
   /^#start/,/^#end/{
      /^#start/{
         n
         r exceptions
      }
      /^#end/!d
   }
' acl.txt

Output:

192.168.0.1
192.168.4.5
#start_exceptions
192.168.88.88
192.168.76.6
#end_exceptions
192.168.5.55

ORIGINAL ANSWER

I think this will work:

sed -e '/^#end/r exceptions' -e '/^#start/,/^#end/d' acl.txt

When it finds /^#end/ it reads in the exceptions file. And it also deletes everything between /#start/ and /#end/.

I have left the matching slightly "loose" for clarity of expressing the technique.

like image 120
Mark Setchell Avatar answered Oct 14 '22 17:10

Mark Setchell


You can use the following, based on Replace string with contents of a file using sed:

$ sed $'/end/ {r exceptions\n} ; /start/,/end/ {d}' acl.txt
192.168.0.1
192.168.4.5
192.168.88.88
192.168.76.6
192.168.5.55

Explanation

  • sed $'one_thing; another_thing' ac1.txt performs the two actions.
  • /end/ {r exceptions\n} if the line contains end, then read the file exceptions and append it.
  • /start/,/end/ {d} from a line containing start to a line containing end, delete all the lines.
like image 26
fedorqui 'SO stop harming' Avatar answered Oct 14 '22 19:10

fedorqui 'SO stop harming'