I'm given a file with many lines like so:

Vinh Tranh:438-910-7449:8235 Maple Street, Wilmington, VM 29085:9/23/63:68900

I need to change the order from Firstname Lastname to Lastname, Firstname. I've gotten this far, but it's still wrong:

sed -e "s/\([^ ]*\) *\(^ ]*\)/\2 \1 /g" datebook

But it outputs as

Tranh:438-910-7449:8235 Vinh Maple Street...

instead of

Tranh, Vinh:438-910...

EDIT: I misunderstood the original question, failing to see that it was using an almost correct BRE syntax. That said...

Your regular expression has some issues:

  • You second capturing group lacks a [ (though this is probably just a transcription issue, since you posted some output that you could not have obtained without this [).
  • To match only the second word with your second capturing group, you probably want to match up to the last character before the first colon - i.e. you want to exclude : from your second capturing group.
  • You don't need the final g flag, since you are interested only in the first match. If you include it, sed will try to match your expression against the remainder of the line too, possibly scrambling it.

As a side note: since you are giving sed just two non-option arguments, the -e option is not necessary; the first non-option argument will be taken as the script to interpret.

The modified version of your command:

sed -e "s/\([^ ]*\) *\([^ :]*\)/\2, \1/"

(I removed the space after the \1 backreference and added a comma after \2 to let it match the sample output you provided).
The result it gives when applied to your original text:

$ echo "Vinh Tranh:438-910-7449:8235 Maple Street, Wilmington, VM 29085:9/23/63:68900" |
sed -e "s/\([^ ]*\) *\([^ :]*\)/\2, \1/"
Tranh, Vinh:438-910-7449:8235 Maple Street, Wilmington, VM 29085:9/23/63:68900
  • Actually, the OP was using perfectly good BRE syntax (well, with a couple of flaws).  The -e option was OK (although unnecessary). The -E became necessary only when you started making unnecessary changes to what the OP had (without explaining them thoroughly). – G-Man Dec 2 '18 at 18:42
  • @G-Man The OP used ERE. The question was then edited, and the edit changed the syntax from almost-ERE to almost-BRE. (Actually, I failed to ask the editor why). This is why I added a clarification to my answer. Would it be better to revert the question to its original spelling or to change my answer? – fra-san Dec 2 '18 at 18:51
  • No, the OP initially did sed -e "s/\([^ ]*\) *\([^ ]*\)/\2 \1 /g" (which is BRE).  They then mistyped it into Stack Exchange as sed -e "s/\([^ ]*\) *\(^ ]*\)/\2 \1 /g" (leaving out the second [) — see the original post.  I believe that the OP merely mistyped the command in Stack Exchange because they show the output that would be expected from the syntactically correct command (including the [). … (Cont’d) – G-Man Dec 2 '18 at 19:23
  • (Cont’d) …  But, since they didn't use code formatting, Stack Exchange ate the backslashes (and two of the asterisks) and displayed the command as “sed -e "s/([^ ]*) (^ ])/\2 \1 /g" ”.   When steeldriver edited the question to add code formatting, the command appeared to change dramatically (the backslashes and asterisks reappeared).   … (Cont’d) – G-Man Dec 2 '18 at 19:23
  • (Cont’d) …  I would suggest (1) leave the bulk of your answer alone (except maybe for removing the backslash before the space between the first name and the last name, unless you can justify it), (2) explain what + does in a regular expression, (3) explain that, because you chose to replace * with + (and not \+), you had to add the -E option, (4) get rid of the first bullet (or change it to point out that -e is unnecessary when you have only one regex), and (5) keep the second and third bullets. – G-Man Dec 2 '18 at 19:23

This would work I believe,

sed 's?^\([[:alpha:]]\{1,\}\)[[:blank:]]\([[:alpha:]]\{1,\}\)?\2, \1?g'


  • SED Separator -> ? (You may replace with /,:, etc.)
  • POSIX Class -> [:alpha:] = [A-Za-z] (Alphabetical)
  • POSIX Class -> [:blank:] = [\s\t] (space and Tab)
  • At least one or more -> {1,}
  • 1st group -> \([[:alpha:]]\{1,\}\)
  • 2nd group -> \([[:alpha:]]\{1,\}\)

[arif@arif test]$ echo "Vinh Tranh:438-910-7449:8235 Maple Street, Wilmington, VM 29085:9/23/63:68900" | sed 's?^\([[:alpha:]]\{1,\}\)[[:blank:]]\([[:alpha:]]\{1,\}\)?\2, \1?'
Tranh, Vinh:438-910-7449:8235 Maple Street, Wilmington, VM 29085:9/23/63:68900
$ echo "Vinh Tranh:438-910-7449:8235 Maple Street, Wilmington, VM 29085:9/23/63:68900"| sed 's/:/ /1'| awk '{$30=$1;$1=$2;$2=$30;print $0}'| sed "s/ /,/1"| sed "s/ /:/1"
Tranh,Vinh:438-910-7449:8235 Maple Street, Wilmington, VM 29085:9/23/63:68900                      Vinh

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.