Malachi
Malachi

Reputation: 33710

How to use sed to replace multiple lines

What would be the right syntax to perform an inplace update to a file from:

"redis"=>array(
    'enabled' => false,

to

"redis"=>array(
    'enabled' => true,

I've tried things like but it's not working

sed -i "s/\"redis\"=>array(\n    'enabled' => false/\"redis\"=>array(\n    'enabled' => true/" input.php 

Upvotes: 2

Views: 86

Answers (4)

potong
potong

Reputation: 58430

This might work for you (GNU sed):

sed '/"redis"=>array($/!b;n;/^\s*'\''enabled'\'' => false,/s/false/true/' file

Look for a line that ends "redis"=>array(, print it and fetch the next line.

If that line contains 'enabled' => false, replace false by true.

Upvotes: 0

Sundeep
Sundeep

Reputation: 23667

With perl:

perl -0777 -ne '$#ARGV==1 ? $s=$_ : $#ARGV==0 ? $r=$_ :
                print s/\Q$s/$r/gr' search.txt replace.txt ip.txt
  • search.txt file containing content to be searched
  • replace.txt file containing content to be used for replacement
  • ip.txt file on which the substitution has to be performed
  • -0777 slurp entire file contents as a single string, so this solution isn't suitable if input file is too large to fit memory requirements
  • $#ARGV is used to know which file is being read
  • $s saves the search text, $r saves the replacement text
  • s/\Q$s/$r/gr here, \Q is used to match search text literally
  • Use perl -i -0777 ... for in-place modification.

See my blog post for more examples and alternatives.

Upvotes: 0

anubhava
anubhava

Reputation: 785196

If you have gnu sed then your attempted approach will fine with -z option:

sed -i -Ez "s/(\"redis\"=>array\(\n[[:blank:]]*'enabled' => )false/\1true/" file

cat file

"redis"=>array(
    'enabled' => true,

Explanation:

  • -z: separate lines by NUL character
  • -E: Enable extended regex mode
  • (\"redis\"=>array\(\n[[:blank:]]*'enabled' => )false: Match "redis"=>array( line followed by line break and 'enabled' => part in capture group #1, followed by false.
  • \1true: puts captured value from group #1 followed by true

Upvotes: 1

Wiktor Stribiżew
Wiktor Stribiżew

Reputation: 626870

You can use

sed -i '/"redis"=>array($/{N;s/\('"'"'enabled'"'"' => \)false/\1true/}' file

See the online demo:

#!/bin/bash
s='"redis"=>array(
    '"'"'enabled'"'"' => false,'
sed '/"redis"=>array($/{N;s/\('"'"'enabled'"'"' => \)false/\1true/}' <<< "$s"

Output:

"redis"=>array(
    'enabled' => true,

Here,

  • /"redis"=>array($/ - match a line that ends with "redis"=>array( string and
  • {N;s/\('"'"'enabled'"'"' => \)false/\1true/} - N appends a newline char and adds the next line to the pattern space, and s/\('enabled' => \)false/\1true/ matches and captures into Group 1 'enabled' => substring and then just matches false and the \1true replaces the match with the Group 1 value + true substring.

Upvotes: 2

Related Questions