AWK reformat portion of results (names) within larger string

AWK reformat portion of results (names) within larger string



My goal is to reformat names from Last First Middle (LFM) to First Middle Last (FML), which are part of a larger string. Here's some sample data:



Name, Address1, Address2
Smith Joe M, 123 Apple Rd, Paris TX
Adams Keith Randall, 543 1st Street, Salinas CA
Price Tiffany, 11232 32nd Street, New York NY
Walker Karen E F, 98 West Ave, Denver CO



What I would like is:



Name, Address1, Address2
Joe M Smith, 123 Apple Rd, Paris
TX
Keith Randall Adams, 543 1st Street, Salinas CA

Tiffany Price, 11232 32nd Street, New York NY
Karen E F
Walker, 98 West Ave, Denver CO



I know how to reorder the first column, but I end up dropping the rest of the row data:


# Return the first colum via comma seperation (name), then seperate by spaces
# If there are two strings but not three (only a last and first name),
# then change the order to first last.

awk -F, 'print $1'| awk -F" " '$2!="" && $3=="" print $2,$1' >> names.txt
awk -F, 'print $1'| awk -F" " '$3!="" && $4=="" print $3,$1,$2' >> names.txt
...# Continue to iterate column numbers



If there's an easier way to put the last string found and move it to the front I'd like to hear about it, but here's my real interest...



My problem is that I want to reorder the space separated fields of the 1st comma separated field (what I did above), but then also print the rest of the comma separated data.



Is there a way I can store the address info in a variable and append it after the space seperated names?



Alternatively, could I do some kind of nested split?



I'm currently doing this with awk in bash, but am willing to use python/pandas or any other efficient methods.



Thanks for the help!




4 Answers
4



The following AWK script, as ugly as it is, works for your inputs (run with awk -F, -f script.awk):


awk -F, -f script.awk



split($1, names, " ");
for (i=2; i<=length(names); i++)
printf("%s ", names[i]);
printf("%s, ", names[1]);
for(i=2; i<NF; i++)
printf("%s,", $i);
print($NF)



Input:


Smith Joe M, 123 Apple Rd, Paris TX
Adams Keith Randall, 543 1st Street, Salinas CA
Price Tiffany, 11232 32nd Street, New York NY
Walker Karen E F, 98 West Ave, Denver CO



Output:


Joe M Smith, 123 Apple Rd, Paris TX
Keith Randall Adams, 543 1st Street, Salinas CA
Tiffany Price, 11232 32nd Street, New York NY
Karen E F Walker, 98 West Ave, Denver CO



The same solution in Python:


import sys
import re

for line in sys.stdin:
parts = re.split('s*,s*', line)
names = parts[0].split()
print(", ".join([" ".join(names[1:] + names[:1])] + parts[1:]))





There was a missing -f option (fixed).
– DYZ
Aug 26 at 3:13


-f





As I said, there was an error in the answer. I fixed it.
– DYZ
Aug 26 at 3:14



Using sed, looks terrible but works:


sed -E '2,$s/^([^ ,]*) ([^ ,]*)( [^,]*)?/23 1/' in



and POSIX version:


sed '2,$s/^([^ ,]*) ([^ ,]*)( [^,]*)*/23 1/' in



output:


Name, Address1, Address2
Joe M Smith, 123 Apple Rd, Paris TX
Keith Randall Adams, 543 1st Street, Salinas CA
Tiffany Price, 11232 32nd Street, New York NY
Karen E F Walker, 98 West Ave, Denver CO





why did you backslash escape everything ?
– oguzismail
Aug 26 at 5:25






what do you mean? you can see all escapes I have in the answer already.
– perreal
Aug 26 at 5:40





I mean why did you escape capturing group parentheses and question mark instead of using extended regexp with -r ?
– oguzismail
Aug 26 at 6:53


-r





Thanks, I thought that would not be POSIX compliant, but I guess it is. Changed.
– perreal
Aug 26 at 7:00





You're right, it's not. -r is just for GNU sed and -E is just for newer versions of GNU sed plus OSX/BSD sed.
– Ed Morton
Aug 26 at 11:01




Another awk. This one works with the header line and Madonna (ie. single word fields):


$ awk ' # using awk
BEGINFS=OFS="," # csv

n=split($1,a," ") # split the first field to a
for(i=n;i>1;i--) # iterate back from the last element of a
a[1]=a[i] " " a[1] # prepending to the first element of a
$1=a[1] # replace the first field with the first element of a
1' file # output



Output:


Name, Address1, Address2
Joe M Smith, 123 Apple Rd, Paris TX
Keith Randall Adams, 543 1st Street, Salinas CA
Tiffany Price, 11232 32nd Street, New York NY
Karen E F Walker, 98 West Ave, Denver CO
Madonna, ...


$ awk '
BEGIN FS=OFS=", "
$1 ~ / /
last = rest = $1
sub(/ .*/,"",last)
sub(/[^ ]+ /,"",rest)
$1 = rest " " last

print
' file
Name, Address1, Address2
Joe M Smith, 123 Apple Rd, Paris TX
Keith Randall Adams, 543 1st Street, Salinas CA
Tiffany Price, 11232 32nd Street, New York NY
Karen E F Walker, 98 West Ave, Denver CO






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

Edmonton

Crossroads (UK TV series)