Replace Text Between Two Strings in File Using Linux Bash

replace a unknown string between two known strings with sed

sed -i 's/WORD1.*WORD3/WORD1 foo WORD3/g' file.txt

or

sed -i 's/(WORD1).*(WORD3)/\1 foo \2/g' file.txt

You might need to escape round brackets, depends on your sed variant.

Replace text between two strings in file using linux bash

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.

Replace unknow string between two strings in bash

sed uses greedy matching so OP's attempt - 2(.*) - is going to match the 1st literal 2( plus the longest string that ends with ); consider the following where our match starts with the first 2( and runs to the last ):

$ echo '(1(...) 2(...) 3(...) 2(abc) 4(...)) more stuff' | sed 's/2(.*)/2(new)/'
(1(...) 2(new) more stuff

To limit the match to the first matching ) there are a few approaches, one idea is to be explicit about what does and does not match, consider:

$ echo '(1(...) 2(...) 3(...) 2(abc) 4(...)) more stuff' | sed 's/2([^)]*)/2(new)/'
(1(...) 2(new) 3(...) 2(abc) 4(...)) more stuff

In this the case we use 2([^)]*) which says to match on 2( followed by any number of characters that are not a ) ([^)]*) followed by a ).

To match on all non-greedy occurrences of 2(...) (where the ... means any non-) character) we can add the global qualifier on the end of the sed script, eg:

$ echo '(1(...) 2(...) 3(...) 2(abc) 4(...)) more stuff' | sed 's/2([^)]*)/2(new)/g'
(1(...) 2(new) 3(...) 2(new) 4(...)) more stuff

Replace String between two patterns

I will assume that the rest of the line is always allow from 1.1.1.1 before the part you want to modify and 2.2.2.2 after the part you want to modify. Try:

string1="allow from 1.1.1.1 9.9.9.9 2.2.2.2"
new=5.5.5.5
string2=$(echo "$string1" | sed "/^\(allow from 1\.1\.1\.1\) .* \(2\.2\.2\.2\)$/s//\1 $new \2/")

If you are not sure of having always 1.1.1.1 or 2.2.2.2, you will have to modify the regex accordingly, which is quite trivial, as in:

string2=$(echo "$string1" | sed "/^\(allow from [^ ]*\) .* \([^ ]*\)$/s//\1 $new \2/")

Replace text between two lines with contents of a file stored in a variable in sed

This might work for you (GNU sed):

sed '/blue/,/gray/!b;//!d;/blue/r file2' file1

For the range of lines between blue and gray, delete lines that do not match either the first or the last lines in the range and read the lines to insert before the last line of the range.

EDIT:

The first sed command /blue/,/grey/!bmatches a range of lines i.e. the lines that range between a line containing blue upto and including a line containing gray. The !b part means if the lines are not in that range then break out of the sed commands i.e. do not do any further sed processing for these lines, just print as normal.

The sed commands following will only affect those lines that are in the range between blue and gray.

The second command //!d means: delete those lines that do not match either the start/end of the range i.e. blue or gray. The // uses the regexp from a previous /.../ command. N.B. a delete command terminates any further sed processing for that line.

The sed commands following will only affect lines that containing either blue or gray.

The third command matches a line containing blue and reads in lines from file2.

N.B. the lines containing blue and grey are processed by sed naturally and printed before the next line is read into the pattern space as are the lines not between blue and gray.

An alternative:

sed '/blue/,/gray/!b;//!d;/gray/e cat file2' file1

And another:

sed -ne '/blue/{p;r file2' -e ':a;n;/gray/!ba};p' file1

Linux: How to replace all text between two lines and substitute it with the output of a variable using sed?

You can probably use this sed:

sed -e '/BEGIN/,/END/ {//!d; /BEGIN/r file.html' -e '}' file

This will insert content of file.html file between BEGIN and END. To save changes back to file:

sed -i -e '/BEGIN/,/END/ {//!d; /BEGIN/r file.html' -e '}' file

Replace all characters between two strings in a line by 'X'

Here is a sed solution:

sed -e :a -e 's/\(%26Name%3d[X]*\)[^X]\(.*%26\)/\1X\2/;ta'

How to use sed/grep to extract text between two words?

sed -e 's/Here\(.*\)String/\1/'


Related Topics



Leave a reply



Submit