对除Bash中的文本以外的数值进行排序

时间:2019-03-27 09:42:11

标签: bash sorting awk

我有一个名为prices.csv的csv文件,如下所示:

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

我想按升序对第二列(价格)进行排序,除了“不可用”的值外,这些值应放在底部。

到目前为止,我所做的是:

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

这将创建以下文件:

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

如您所见,这会将价格为“不可用”的产品放在顶部而不是底部。如何使用通用代码将文本放在底部?

2 个答案:

答案 0 :(得分:2)

如果您有gnu-awk,则可以使用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

或者,您可以使用head + tail + sort命令,如下所示:

head -n 1 file && sort -t, -k2V <(tail -n +2 file)

答案 1 :(得分:1)

您可以考虑使用版本排序而不是数字排序:

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

有关版本排序的更多信息,请参见here。请注意,这会将标头移到后面。您可以使用此方法:

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

但这太丑陋了,在这一点上,我将切换到Anubhava的解决方案。

您可以执行此操作的另一种方法是进行可笑的替换:

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

将标题保留在原处。