My code goes like this:

cat file.ign | sed 's/^([^A-Za-z0-9]+ )/<ignore>\1<\/ignore>/g'

Yet I receive an error saying :

sed: 1: "s/^([^A-Za-z0-9]+ )/<ig ...": \1 not defined in the RE

Parentheses are literal in basic regular expression (BRE) syntax - to make them denote a capture group, they must be escaped, as \( and \)

Additionally, as noted in a comment by @BenjaminW, + is also literal in BRE. GNU sed supports \+ as a quantifier in BRE:

sed 's/^\([^A-Za-z0-9]\+ \)/<ignore>\1<\/ignore>/g'

(but other implementations might not). Alternatively, turn on extended regular expression (ERE) mode using the -E or -r command line switch as appropriate (check your version's documentation):

sed -E 's/^([^A-Za-z0-9]+ )/<ignore>\1<\/ignore>/g'

or use the POSIX-compliant quantifier \{1,\}

sed 's/^\([^A-Za-z0-9]\{1,\} \)/<ignore>\1<\/ignore>/g'

ASIDE the g (global replacement) modifier won't have any effect here, since ^ anchors the expression to the start of the pattern (which can occur only once per line)

  • 1
    Furthermore, + is only avalable in ERE; GNU sed supports it as an extension in BRE, but is has to be escaped. – Benjamin W. Feb 7 '19 at 0:39
  • @BenjaminW. oops yes that's a good point - I missed that – steeldriver Feb 7 '19 at 0:40
  • The -E also is GNU or FreeBSD sed, not in POSIX. If you're going to recommend a non-POSIX solution, mentioning that might help the reader. – Thomas Dickey Feb 7 '19 at 1:20
  • sed 's#^[^A-Za-z0-9][^A-Za-z0-9]* #<ignore>&</ignore>#' will do the same in any sed, and it's hardly uglier than \(..\{1,\}..\)/..<\/../ ;-) – pizdelect Feb 7 '19 at 5:47
  • 1
    @ThomasDickey But it looks like it has been accepted - not sure when it'll make it into the standard, though. – Benjamin W. Feb 7 '19 at 14:10

Using GNU sed, you can invoke as sed -E or else you can escape the parentheses in order to get the back-reference working, but if you're not using GNU sed, you can't rely on back references; POSIX sed doesn't (yet) support the -E or -r argument for Extended Regular Expressions (ERE) nor does it support GNU's Basic Regular Expression (BRE) backslash notation. (Here's more on POSIX ERE & BRE, though it doesn't speak in much depth about GNU's BRE implementation allowing escaping into ERE functionality.)

Fortunately, (in this case) you don't need ERE. This should work for you:

sed 's/^[^A-Za-z0-9][^A-Za-z0-9]* /<ignore>&<\/ignore>/' file.ign

BRE doesn't support the + quantifier, so I needed to double the nonword character set so it would be "one or more" by requiring "one" and then "zero or more" of them. The ampersand (&) denotes the entire match. There's no need to have parentheses around everything in this case. (The beginning-of-line anchor ^ is zero-width and doesn't matter here.)

I removed the cat because it's unnecessary. I also removed your /g modifier because the ^ anchor means this can only match once per line, so you'll never get a second match and therefore a global replacement doesn't do anything.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.