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.

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?

share|improve this question

6 Answers 6

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}'
share|improve this answer

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
123|last1,first1|foo|bar|date|baz
456|last2,first2|foo|bar|date|baz
789|last3,first3|foo|bar|date|baz
share|improve this answer

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

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.

share|improve this answer

Try:

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
}
share|improve this answer
up vote 0 down vote accepted

+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)
harris,charles
johnson,bill
dylan,robert
woodcock,john
wood,barry
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.