2

I have a valid RegEx pattern that captures three groups of a string. I'm trying to use it in a sed script to perform a find & replace operation, but I keep getting the following error:

sed: -e expression #1, char 49: Unmatched ( or \(

My script looks like this:

#!/usr/bin/env bash

pattern="^.*(require\(require\()(.+)(\);$)"
replace="require(\2;"
sed -i "s/$pattern/$replace/g" /usr/lib/node_modules/deployd/lib/type-loader.js

The file I'm trying to edit has a line that reads:

var c = require(require('path').resolve(path) + '/node_modules/' + file);

...and my desired result is:

var c = require('path').resolve(path) + '/node_modules/' + file;

I've confirmed my RegEx here: http://regex101.com/r/qO4jE5/1

...and double-checked it here: http://regexraptor.net/

Any idea what I'm doing wrong?

Shaun Scovil
  • 3,703
  • 4
  • 31
  • 54
  • There is no such thing as a "valid regexp". Every regexp is only "valid" in the context of the tool you are going to use it in and the options and delimiters you are using in the call to that tool. A regexp that's "valid" in awk may not be in sed, a regexp that's "valid" for `sed 's/regexp//'` may not be for `sed 's#regexp##'` or `sed -r 's/regexp//'`, etc. – Ed Morton Aug 23 '14 at 18:53
  • 1
    @EdMorton I suppose if you want to split hairs, I could have said "A RegEx that achieves the desired result in JavaScript, PHP, Python and Bash does not work with sed"...but for the sake of brevity I think using the word 'valid' is okay here. :-) – Shaun Scovil Aug 23 '14 at 19:02
  • You would be wrong in thinking that, stating that an RE is "valid" without stating what tool it's valid for or even whether you think it's a "valid" BRE or ERE or PerlRE or ... is misleading at best. Your RE contains `.+`, for example which in sed means any single character followed by a plus character. That is "valid" syntax for any RE but is that what you want it to mean? In awk or GNU sed with -r it means any single character repeated 1 or more times. Maybe that's the sort of "valid" you mean? – Ed Morton Aug 24 '14 at 11:56

3 Answers3

3

Normal sed uses BRE, Basic Regular Expressions. In BRE, the capturing groups () must be escaped like this \(,\) and to match a literal ) symbol, just ) would be enough.

Example:

$ echo "var c = require(require('path').resolve(path) + '/node_modules/' + file);" | sed 's/^\(.*\)require(require\(.*\));$/\1require\2;/'
var c = require('path').resolve(path) + '/node_modules/' + file;
Avinash Raj
  • 160,498
  • 22
  • 182
  • 229
3

GNU sed supports extended regular expressions if you give it the -r flag.

sed -i.bak -r 's/^(.*?require\()require\((.*)\)/\1\2/' file

Ideone Demo

hwnd
  • 65,661
  • 4
  • 77
  • 114
1

You can use this sed:

sed -i.bak -r 's/^(.* )(require\(require\()(.+)(\);)$/\1require(\3;/' file
var c = require('path').resolve(path) + '/node_modules/' + file;

OR on OSX use sed -E:

sed -i.bak -E 's/^(.* )(require\(require\()(.+)(\);)$/\1require(\3;/' file
var c = require('path').resolve(path) + '/node_modules/' + file;
anubhava
  • 664,788
  • 59
  • 469
  • 547
  • Thanks for the quick response! Avinash beat you to it, so I accepted his answer...but I appreciate your help as well. – Shaun Scovil Aug 23 '14 at 17:37