I have a sample file:-

[root@localhost base_filters]# cat shortlist
2233|charles harris  |g.m.     |sales     |12/12/52| 90000
9876|bill johnson    |director |production|03/12/50|130000
5678|robert dylan    |d.g.m.   |marketing |04/19/43| 85000
2365|john woodcock   |director |personnel |05/11/47|120000
5423|barry wood      |chairman |admin     |08/30/56|160000

I wanted to flip the names in the file such that there is a comma , after the last name i.e for example a name should appear as harris,charles.

I tried the following command:-

[root@localhost base_filters]# tr -s ' ' < shortlist | cut -d\| -f2 | cut -d' ' -f2,1
charles harris
bill johnson
robert dylan
john woodcock
barry wood

I want last name to appear first so I specified field 2 and then 1 but this doesn't seem to work. Any Ideas about this?


This is done easily using awk. First print out the name, then pipe the output to awk again (this time using space as the file separator).

awk -F "|" '{print $2}' extract.txt | awk -F " " '{print $2 "," $1}'

The following function will use only Bash built-ins ( in case that you want to use Bash ) to do what you want:

foo () 
    local filename="$1"

    while IFS='|' read -r pre name suf; do
        l="$pre|${name#* },${name% *}|$suf";
        printf '%s\n' "$l";
    done < "$filename"

The IFS variable is set to | and 'read' reads every line at a time from "$1" ( your file ) and divides it into three parts, $pre $name and $suf, according to the IFS value.

$pre value is set to be the field before the name, $name is set to be the name itself which you want to swap ( the second field ) and $suf is the rest of the line.

I use Parameter Expansion ( also search for Parameter Expansion in man bash ) to split the $name field.

"${name#* }" will cut the first name, leaving us with the last name.

"${name% *}" will cut the last name, leaving us with the first name.

Usage: foo [/path/to/file.txt]

Sample output:

nylon100@~$ cat>file.txt
123|first1 last1|foo|bar|date|baz
456|first2 last2|foo|bar|date|baz
789|first3 last3|foo|bar|date|baz

nylon100@~$ foo file.txt

Yes, cut doesn't change the order, it just selects data from each line.

You'd need to use sed or awk like:

sed 's/^\([^|]*|\)\([^|]\{1,\}\) \([^ |]\{1,\}\)/\1\3,\2/'

The man page of cut says

Selected input is written in the same order that it is read, and is written exactly once.

So you have to use another tool instead of cut. For example sed, awk, perl, python or bash.



tr -s ' ' < shortlist | cut -d\| -f2 | tr '\n' ' ' | tac -s' ' | \
  sed -e 's/^[[:space:]]//' -e 's/  /\n/g' | sort

Or, if you have many such files:

sortnames () {
  tr -s ' ' < $1 | cut -d\| -f2 | tr '\n' ' ' | tac -s' ' | \
    sed -e 's/^[[:space:]]//' -e 's/  /\n/g' | sort

+1 all, for their support :). I found an even simpler solution:-

[root@localhost base_filters]# paste -d, <(cut -d\| -f2 shortlist| cut -d' ' -f2) <(cut -d\| -f2 shortlist| cut -d' ' -f1)

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.