Comparing:
echo 'abc def' | sed 's/\([a-zA-Z0-9][a-zA-Z0-9]+\) \([a-zA-Z0-9][a-zA-Z0-9]+\)/\2 \1/'
abc def
echo 'abc def' | sed 's/\([a-zA-Z0-9][a-zA-Z0-9]*\) \([a-zA-Z0-9][a-zA-Z0-9]*\)/\2 \1/'
def abc
echo 'abc def' | sed 's/\([a-zA-Z0-9]+\) \([a-zA-Z0-9]+\)/\2 \1/'
abc def
echo 'abc def' | sed 's/\([a-zA-Z0-9]*\) \([a-zA-Z0-9]*\)/\2 \1/'
def abcThe intention is to swap 'abc' and 'def', why are some of these examples not working?
In the + versions: I expected [a-zA-Z0-9]+ would match things like 'a', 'ab' and 'abc' (up to the space) and swap them. I expected the [a-zA-Z0-9][a-zA-Z0-9]+ version to match 'ab' and 'abc', which would work to
Is there any difference between the * versions, besides that the one with a single?
Isn't [a-zA-Z0-9][a-zA-Z0-9]* the same as [a-zA-Z0-9]+? That is, match a string of at least one alphanumeric character?
1 Answer
The POSIX "Basic" regex language used by sed does not have the + operator, so [a-zA-Z0-9]+ matches exactly one alphanumeric character – followed by a literal plus-sign.
It does have the \{x,y\} operator to accept the specified number of matches, for example:
$ echo 'abc def' | sed 's/\([a-zA-Z0-9]\{2,\}\) \([a-zA-Z0-9]\{2,\}\)/\2 \1/'
def abcUse sed -E to enable the "Extended" regex mode, where + is a special character. This will also change how parentheses work – in extended mode, bare ( ) are used for capture groups and similarly bare { } are used for number of matches, the opposite of basic mode.
$ echo 'abc def' | sed -E 's/([a-zA-Z0-9][a-zA-Z0-9]+) ([a-zA-Z0-9][a-zA-Z0-9]+)/\2 \1/'
def abc
$ echo 'abc def' | sed -E 's/([a-zA-Z0-9]{2,}) ([a-zA-Z0-9]{2,})/\2 \1/'
def abcGNU sed/grep also allow you to use \+ in basic mode but this is not portable to other operating systems. See info "(sed)BRE syntax" and info "(sed)ERE syntax" (or man 7 regex) for a comparison of the two modes.