Can anybody give me the difference between the following two commands in the context of escaping parentheses, or refer some document that would clear my doubt.


$ echo `expr match "$string" 'abc[A-Z]*.2'` #Result is 8, the count of matched characters

$ echo `expr match "$string" '\(abc[A-Z]*.2\)'`   #Result is abcABC12, the matched characters

What is the actual significance of escaped parentheses \(...\) here ?


That refers to GNU expr (part of coreutils) and the \( and \) are marking a group as docmented in 16.4.1 String expressions:

If the match succeeds and regex uses ‘\(’ and ‘\)’, the : expression returns the part of string that matched the subexpression; otherwise, it returns the number of characters matched.

The documentation refers to 3 Regular Expressions in grep for details. The syntax of regular expressions is documented in POSIX:

Consistent with the whole match being the longest of the leftmost matches, each subpattern, from left to right, shall match the longest possible string. For this purpose, a null string shall be considered to be longer than no match at all. For example, matching the BRE "\(.*\).*" against "abcdef", the subexpression "(\1)" is "abcdef", and matching the BRE "\(a*\)*" against "bc", the subexpression "(\1)" is the null string.

POSIX expr mentions regular expressions with the : operator:

expr1 : expr2

but goes on to say:

The use of string arguments length, substr, index, or match produces unspecified results.

so this particular usage appears to be an extension.

The POSIX usage of : is documented in detail in the section Matching Expression; the match operator seen here corresponds to the :, but its position is changed to an prefix operator (before the two operators) where POSIX : uses infix (between the two operands).

Viewed as a group, the length, etc., can be considered either as an extension (a nonstandard feature providing functionality not achievable via a particular utility) or merely nonstandard (an incompatible way of performing a function which can be done via a different method). This one is mixed: the POSIX shell gives similar functionality for length, etc., as documented in the section on Parameter Substitution, i.e., ${#parameter}. However substr and index have no apparent exact equivalent. (Although the syntax differs, the entire group is probably based on awk).

  • The capture group matched in expr is also specified by POSIX, it's not GNUism. – cuonglm Nov 30 '15 at 9:30
  • I was aware of that, but offhand did not recall this case - will clarify further as as needed. – Thomas Dickey Nov 30 '15 at 9:34
  • Note that those length/match are mentioned as allowed extensions for applications to be able to guard against things like expr length = "$var" which is not guaranteed to work with every implementation. length "$var" can be implemented with "$var" : '.*'. substr and index can also be implemented with the : operator. In any case, all those are broken and expr should probably be avoided as they fail with some values or have unwanted side effects. – Stéphane Chazelas Nov 30 '15 at 11:59
  • (a) I was not advising for/against the usage, but explaining it, and (b) I don't see the particular wording in POSIX regarding "allowed extensions"). POSIX is never explicit enough. – Thomas Dickey Nov 30 '15 at 12:02
  • That was just a note, not a critic on your answer. – Stéphane Chazelas Nov 30 '15 at 12:13

When the pattern contain the subexpression \(...\), the string matched will be return. This behavior is specified by POSIX:

Alternatively, if the pattern contains at least one regular expression subexpression "[\(...\)]", the string matched by the back-reference expression "\1" shall be returned. If the back-reference expression "\1" does not match, then the null string shall be returned.

Note that you should change the command to:

expr "$string" : '\(abc[A-Z]*.2\)'

to make it work in all POSIX compliant expr. The use of match is unspecified.

  • More like LC_ALL=C expr "x$string" : 'x\(abc[A-Z]*.2\)' – Stéphane Chazelas Nov 30 '15 at 12:14

Backslashed parentheses \(...\) create a "capture group". expr match seems to return the first capture group.

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.