2

Preamble

Maybe you want to convert this:

aaaa

To:

1aaa1

So let's propose this:

echo aaaa | sed --regexp-extended 's/(.*)a/1\11/'
→
1aaa1

Question

Is 1\11 a 100% valid unambiguous sed pattern? Am I complying with all sed good practice with such replacement?

I mean that 1\11 maybe could be both of these:

  1. replace with char 1, then the 1° matched group, then another char 1 (→ current behavior)
  2. replace with char 1, then the 11° matched group (→ causing an exception)

At the moment it seems my sed version has the first interpretation. Anyway I don't know if this is documented or if it can be wrote in a better way in sed.

Thank you for any clarification. In the meanwhile I will not build a castle on this.

At the moment I'm using GNU sed 4.7.

1

2 Answers 2

2

As said by the user @QuartzCristal, in the GNU's sed man page there is this note:

s/regexp/replacement/

Attempt to match regexp against the pattern space. If successful, replace that portion matched with replacement. The replacement may contain the special character & to refer to that portion of the pattern space which matched, and the special escapes \1 through \9 to refer to the corresponding matching sub-expressions in the reg‐ exp.

Coming from generic programming languages (like Perl) where there is no such limitation from 1 to 9 (since for example you can write 1{$19}1), I was not aware of this limitation in sed. So, I understand that at the moment the syntax is just 100% correct and cannot be onterpreted in no other way.

This answer is valid for GNU sed. Not sure it's a POSIX definition.

3
  • 1
    One language that allows for backreferences is Perl. But such references are actually written ${16}. So, no expectations of confusion. Sep 6, 2022 at 16:44
  • That's exactly the syntax that I was not finding in sed. Good to know that there is a reason for this lack. I'm integrating in the answer. Sep 6, 2022 at 16:46
  • Note that perl can also happily handle $11, it just also supports ${11} to avoid ambiguity. So echo abcdefghijklmn | perl -lpe 's/(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.).*/$11/' works, but echo abcdefghijklmn | perl -lpe 's/(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.).*/$111/' fails and requires echo abcdefghijklmn | perl -lpe 's/(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.).*/${11}1/'
    – terdon
    Sep 6, 2022 at 16:50
1

There is a description in POSIX that reads:

The back-reference expression '\n' shall match the same (possibly empty) string of characters as was matched by a subexpression enclosed between "(" and ")" preceding the '\n'. The character 'n' shall be a digit from 1 through 9, specifying the nth subexpression (the one that begins with the nth "(" from the beginning of the pattern and ends with the corresponding paired ")" ).

Which will avoid any \10 or \11.

That's the syntax for BRE, but we do not need to worry about ERE in POSIX as those do not allow backreferences.

The Manual for GNU sed states the same. I do not believe there is any sed that allows more than \1...\9 backreferences.

Also, the right side of a replacement s/// may contain references to capture parentheses. Those are not clearly delimited in Posix:

The characters "\n", where n is a digit, shall be replaced by the text matched by the corresponding back-reference expression.

But it seems to be using the same rule as for back-references.

GNU sed does state that clearly:

Back-references are specified with backslash and a single digit (e.g. '\1').

One language that allows more backreferences is Perl. But in that language, backreferences with more than one digit are written ${23}. I imagine that such a provision, or similar, is generally used to avoid confusions.

0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .