Replace Text Between Two Lines with Contents of a File Stored in a Variable in Sed

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 a word with multiple lines using sed?

If you build your multiple line text with "\n"s, this will work with a simple sed command as:

DATA=`echo ${DATA} | tr '\n' "\\n"`
#now, DATA="line1\nline2\nline3"
sed "s/_data_/${DATA}/" mail.tpl

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.

Replacing lines between two specific strings - sed equivalent in cmd

Use PowerShell, present from Windows 7 on.

## Q:\Test\2018\10\30\SO_53073481.ps1
## defining variable with a here string
$Text = @"
Many lines
many lines
they remain the same

[REPORT]

some text
some more text412

[TAGS]

text that I Want
to stay the same!!!
"@

$Text -Replace "(?sm)(?<=^\[REPORT\]`r?`n).*?(?=`r?`n\[TAGS\])",
"`nmy text goes here`nAnd a new line down here`n"

The -replace regular expression uses nonconsuming lookarounds

Sample output:

Many lines
many lines
they remain the same

[REPORT]

my text goes here
And a new line down here

[TAGS]

text that I Want
to stay the same!!!

To read text from file, replace and write back (even without storing in a var) you can use:

(Get-Content ".\file.txt" -Raw) -Replace "(?sm)(?<=^\[REPORT\]`r?`n).*?(?=`r?`n\[TAGS\])",
"`nmy text goes here`nAnd a new line down here`n"|
Set-Content ".\file.txt"

The parentheses are neccessary to reuse the same file name in one pipe.

Sed command to change a string at only desired place

Is there any way to replace the string using a WHERE clause so I can replace the string only where I want?

sed does not have SQL-style WHERE clauses, but commands can have "addresses" that define subsets of input lines to operate upon. These can take several forms. Regular expressions are perhaps the most common, but there are also line numbers, and a couple of special forms. You can also have inclusive ranges built from simple addresses. An address range would be a reasonably good way to address the problem you present.

For example,

sed -i '/^\s*-\s*stage:\s*Moto_Dev/,/^\s*-/ s/dependsOn: Build/dependsOn: Test/' input

Explanation:

  • The -i command-line flag tells sed to work "in-place", which really means that it will replace the original file with one containing sed's output.

  • The /^\s*-\s*stage:\s*Moto_Dev/,/^\s*-/ is a range address, consisting of a regex for the range start (/^\s*-\s*stage:\s*MotoDev/) and one for the range end (/^\s*-/).

    • /^\s*-\s*stage:\s*Moto_Dev/ matches the beginning of the section in which you want the change to be made, with some flexibility around the exact amount of whitespace at certain positions. For brevity and clarity, it uses \s to represent a single space or tab character. That is a GNU extension, but if you cannot depend on GNU sed then there are other ways to express the same thing.
    • /^\s*-/ matches the beginning of the next section, as you have presented the input. It could be made more specific if it were necessary to be more selective.
      The range includes its endpoints, but that does not appear to be a problem for the task at hand.
  • There is only one such range in the input presented, and that range contains the line you want to modify. The specified substitution, s/dependsOn: Build/dependsOn: Test/, is performed on each line in the range, but only the one contains a match to be replaced. All others in the range will be unaffected.

  • No commands at all are specified for lines outside the range, so they too will be unaffected.


You also asked,

I stored the desired piece of code in a variable. Can I use that
variable in a sed command? For example,

sed -i "s/condition: succeeded('Fair_PreProd')/condition: succeeded('Fair_UAT')/g" $folder_path/$file_name

sed does not expand shell-style parameter references, but you don't need it to do. The variable references in that command are expanded by the shell itself, before it executes the resulting command, so

  • yes, you may use them, and
  • it's not a question of using shell variables with sed in particular.


Related Topics



Leave a reply



Submit