serilain
serilain

Reputation: 451

sed not behaving properly w/ capture group; can't see what's wrong

Sorry to have to post this as it seems rather basic, but I can't tell why the heck it's not working:

sed -r -i.bak 's/-- Database: (.*?)\n/CREATE DATABASE \1\n/g' file.sql

The file contains a line that looks like this:

-- Database: `omptest`

and doing the exact same thing as a find/replace in sublime works fine:

Find: -- Database: (.*?)\n
Replace with: CREATE DATABASE \1\n

sed doesn't seem to like the \1 unless I either escape the parentheses surrounding the capture group or use -r for expanded regex -- otherwise it throws sed: -e expression #1, char 53: invalid reference \1 on `s' command's RHS.

Regardless, when I use the -r or escape the parentheses, it doesn't edit the file, as though it hasn't worked. I have no idea why.

I think I'm either forgetting or just now discovering some weird property of sed regex but I can't for the life of me figure out what the issue might be. Help appreciated!

Upvotes: 0

Views: 607

Answers (1)

Wintermute
Wintermute

Reputation: 44023

sed works on a line-based basis and doesn't see the newlines in a file (unless you do special things). Use

#                                 vvv----------------vvv--- no newlines
sed -r -i.bak 's/-- Database: (.*?)/CREATE DATABASE \1/g' file.sql

Addendum: Three more things to note, perhaps:

  1. .*? does exactly the same as .* in sed. The former can be used for non-greedy matching in some other regex engines but not in sed. The ? does not do any harm, but it doesn't do anything at all either.
  2. Since the regex matches greedily to the end of the line, the /g flag doesn't have any impact. There's never going to be a second match because the first extends to the end of the line.
  3. Since the capture group is put right back where it was found, it doesn't really need to be captured it in the first place.

From the first two observations, we might arrive at a simplified version of the original script:

sed -r -i.bak 's/-- Database: (.*)/CREATE DATABASE \1/' file.sql

...and because of the third, we could ditch those changes again and just use

sed -i.bak 's/-- Database: /CREATE DATABASE /' file.sql

instead.

Upvotes: 4

Related Questions