1

I have a csv file called prices.csv that looks like this:

Name, Price, Description
Apple, 2.85, fruit
Kiwi, 1.96, fruit
Banana, 0.99, fruit
Peach, Not available, fruit
Orange, 2.02, fruit

I would like to sort the second column (Price) in ascending order, except for the values that are 'Not available', these should be placed at the bottom.

What I've done so far is this:

sort -t, -k2,2 -n prices.csv > ordered_prices.csv

This creates the following file:

Name, Price, Description
Peach, Not available, fruit
Banana, 0.99, fruit
Kiwi, 1.96, fruit
Orange, 2.02, fruit
Apple, 2.85, fruit

As you can see this places the products with price 'Not available' at the top instead of at the bottom. How do I place the text at the bottom with generic code?

anubhava
  • 761,203
  • 64
  • 569
  • 643
sander
  • 141
  • 2
  • 7

2 Answers2

2

If you have gnu-awk then you can do this using PROCINFO:

awk -F ', ' 'NR == 1 {
   print
   next
}
$2+0 == $2 {
   a[NR] = $2
   rec[NR] = $0
   next
}
{
   rest = rest $0 RS
}
END {
   PROCINFO["sorted_in"] = "@val_num_asc"
   for (i in a)
      print rec[i]
   printf "%s", rest
}' file

Name, Price, Description
Banana, 0.99, fruit
Kiwi, 1.96, fruit
Orange, 2.02, fruit
Apple, 2.85, fruit
Peach, Not available, fruit

Alternatively you can use head + tail + sort command like this:

head -n 1 file && sort -t, -k2V <(tail -n +2 file)
anubhava
  • 761,203
  • 64
  • 569
  • 643
1

You might consider using version sort instead of a numeric sort:

$ sort -t, -k2,2V  prices.csv > ordered_prices.csv

More information about version sorting can be found here. Note that this will move your header to the back. You could use this method:

$ OUTPUTFILE=outputfile
$ awk -v out="$OUTPUTFILE" '(NR==1){print > out; close(out)}(NR>1)' inputfile \
  | sort -t, -k2,2V > $OUTPUTFILE

But that is super ugly and at this point I would switch to the solution of Anubhava.

Another way you could do this is by doing a ridiculous substitution:

$ sed '2,$s/\([[:alpha:]]\+\)/999999\1/g' | sort -t, -k2n | sed 's/999999//g'

which keeps the header in place.

kvantour
  • 25,269
  • 4
  • 47
  • 72