Sign up ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It's 100% free, no registration required.
$ echo "104_Fri" | sed 's/^\([0-9]+\)_\([A-Za-z]+\)$/\1;\2/'

I would like to match the digits at the beginning and the letters at the end - each as a group. Afterwards I want to output the first group, a semicolon and then the second group.

I would expect this expression to yield:


Why does this not work?

share|improve this question

5 Answers 5

up vote 7 down vote accepted

You must escape plus symbol +, too:

$ echo "104_Fri" | sed 's/^\([0-9]\+\)_\([A-Za-z]\+\)$/\1;\2/'
share|improve this answer

Backslash the +:

$ echo "104_Fri" | sed 's/^\([0-9]\+\)_\([A-Za-z]\+\)$/\1;\2/'

Note that + is not a standard basic regular expression metacharacter, and so doesn't have portable behaviour in sed even when backslashed.

You should use sed -r or sed -E to enable extended regular expressions instead, in which you don't need to backslash any of these characters. These options are also non-standard, but at least you'll get an error if they're unsupported rather than mysterious failures. The options are supported by GNU sed and all the main BSD derivatives (FreeBSD, OpenBSD, NetBSD, OS X), but not in many of the commercial Unix versions.

If you need extended regular expressions truly portably, use awk, which always uses them.

share|improve this answer
Of course, x+ is easily rewritten as xx* if the portable subset of sed must be used. –  hvd Jul 28 '14 at 13:21
TIL why ab+ doesn't work in vim while ab* does! –  Kevin G. Jul 28 '14 at 15:04
If everyone used PCRE (or a subset of it, such as POSIX ERE), the world would be a happier place. –  nyuszika7h Jul 28 '14 at 15:14

Add the -r option ;-) for extended regexps, and the need to \ active content diminishes.

$ echo "104_Fri" | sed -re 's/^([0-9]+)_([A-Za-z]+)$/\1;\2/'

As the Q is written, (no background data) the splitting-task could be done in several other simpler ways:

$ echo "104_Fri" | tr '_' ';'

$ echo "104_Fri" | sed  's/_/;/'

... to name two.

share|improve this answer

You might also alternate addresses. You wind up using far fewer crazy backslashes that way.

sed -n '/._./{/^[0-9]*.[A-Za-z]*$/s/_/;/p;}'

sed -n '/[^0-9].*_.*[^A-Za-z]/d;/._./s/_/;/p'
share|improve this answer
+1 for the ._. smiley. –  nyuszika7h Jul 28 '14 at 15:08

I suggest using Perl instead, as it comes preinstalled on most Unix systems:

$ echo '104_Fri' | perl -p -e 's/^([0-9]+)_([A-Za-z]+)$/$1;$2/'

You can simplify that further:

$ echo '104_Fri' | perl -p -e 's/^(\d+)_([a-z]+)$/$1;$2/i'

Note: If your input is really as simple as in the question, a simple tr will do:

$ echo '104_Fri' | tr '_' ';'

Or with Perl:

$ echo '104_Fri' | perl -p -e 's/_/;/'
share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

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