-1

I'm trying to replace the text in a file between # begin and # end as follows:

# begin

# [block]
# param1=""
# param2=""

# end

to read as:

# begin

[block]
param1="value1"
param2="value2"

# end

Basically, I'm uncommenting the [block] line as well as the param values that fall under it.

2 Answers2

3

A simpler solution that avoids unneeded loops, using Mac OS X's BSD sed1:

/# begin/,/# end/ {    # Search only within this range of text.
  //!s/^# //           # Excluding range borders, delete /^# / from each line.
}

Testing:

▶ cat > FILE <<EOF
aaa
bbb
# begin

# [block]
# param1=""
# param2=""

# end
ccc
ddd
EOF
▶ sed -i '' '/# begin/,/# end/{//!s/^# //;}' FILE
▶ cat FILE
aaa
bbb
# begin

[block]
param1=""
param2=""

# end
ccc
ddd

Further explanation:

  • Note that the empty regular expression // repeats the last regular expression match. Thus, //! negates that. And /PAT1/,/PAT2/{ //! X } has the effect of excluding both /PAT1/ and /PAT2/ for X.

1 And also tested using GNU sed.

Alex Harvey
  • 14,494
  • 5
  • 61
  • 97
2

by sed:

sed '/^# begin/,/^# end/{/^# \(begin\|end\)/b a;s/^# *//; :a}' your_file > new_file

it's slightly complicated:

/^# begin/,/^# end/         # match from begin to end
{
    /^# \(begin\|end\)/b a; # if it's begin or end, jump to label a
    s/^# *//;               # delete all sharps
     :a                     # label a locates at the end
}

demo:

$ cat f
# begin

# [block]
# param1=""
# param2=""

# end

$ sed '/^# begin/,/^# end/{/^# \(begin\|end\)/b a;s/^# *//; :a}' f
# begin

[block]
param1=""
param2=""

# end
Jason Hu
  • 6,239
  • 1
  • 20
  • 41
  • This is great! Thanks! Now what if "# begin" and "# end" didn't always exist and the # [block] and param section existed somewhere in the middle...how would I be able to replace it still? –  Apr 02 '15 at 21:30
  • it will replace everything after the first discovery of begin and till the first discovery of end. – Jason Hu Apr 03 '15 at 01:26
  • Gotcha...is there I way I can make it uncomment the lines beginning at `# [block]` and ending at the first instance of a carriage return...disregarding the `# begin` and `# end` lines? –  Apr 03 '15 at 18:27
  • @AndrewWeiss don't get it. sed defaultly parses file line by line which means your file should be multi-lined. maybe you can update you question with another example. – Jason Hu Apr 03 '15 at 18:39
  • This doesn't work on Mac OS X: `sed: 1: "/^# begin/,/^# end/{/^# ...": unexpected EOF (pending }'s)` – Keith Aug 21 '17 at 19:56
  • @Keith a quick search indicates the sed shipped with mac is not working the same as gnu sed: https://stackoverflow.com/questions/15467616/sed-gives-me-unexpected-eof-pending-s-error-and-i-have-no-idea-why – Jason Hu Aug 21 '17 at 20:00
  • 1
    MacOS `sed` dislikes semicolons after labels, I think you need to use a literal newline instead of a semicolon. – tripleee May 02 '19 at 09:39