15

I have a file named ip-list with two columns:

IP1  <TAB>  Server1
IP2  <TAB>  Server2

And I want to produce:

Server1  <TAB>  IP1
Server2  <TAB>  IP2

What's the most elegant, shortest Linux command line tool to do it?

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
Adam Matan
  • 128,757
  • 147
  • 397
  • 562

4 Answers4

20

Use awk:

awk '{print $2,$1}' ip-list

That should give you what you want.

Chris Scott
  • 1,721
  • 14
  • 27
7

More than two columns

printf "\
1 2 3 4
5 6 7 8
" | awk '{for(i=NF;i>1;i--)printf "%s ",$i;printf "%s",$1;print ""}'

Output:

4 3 2 1
8 7 6 5

See also: https://unix.stackexchange.com/questions/46275/swapping-an-unlimited-number-of-columns

Tested in GNU Awk 4.0.1.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
5

The simplest solution is:

awk '{print $2 "\t" $1}'

However, there are some issues. If there may be white space in either of the fields, you need to do one of: (depending on if your awk supports -v)

awk -v FS='\t' '{print $2 "\t" $1}'
awk 'BEGIN{ FS="\t" } {print $2 "\t" $1}'

Alternatively, you can do one of:

awk -v OFS='\t' '{print $2,$1}'
awk 'BEGIN{ OFS="\t" } {print $2,$1}'
awk -v FS='\t' -v OFS='\t' '{print $2,$1}' # if allowing spaces in fields

One of the comments asks, 'where does the filename go'? awk is used as a filter, so it would typically appear as:

$ some-cmd | awk ... | other-cmd

with no filename given. Or, a filename can be given as an argument after all commands:

$ awk ... filename
William Pursell
  • 204,365
  • 48
  • 270
  • 300
1

perl -pi -e 's/^([^\t]+)\t([^\t]+)$/\2\t\1/' yourfile.csv

perl -pi -e 'split("\t"); print "$_[1]\t$_[0]"'

The first one probably works on sed, too.

hhaamu
  • 6,851
  • 3
  • 19
  • 13