Take the 2-minute tour ×
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/'
104_Fri

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:

104;Fri

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/'
104;Fri
share|improve this answer

Backslash the +:

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

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
2  
Of course, x+ is easily rewritten as xx* if the portable subset of sed must be used. –  hvd Jul 28 at 13:21
    
TIL why ab+ doesn't work in vim while ab* does! –  Kevin G. Jul 28 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 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/'
104;Fri

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

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

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

... 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  
+1 for the ._. smiley. –  nyuszika7h Jul 28 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

 
discard

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.