我有以下输入csv文件:
"aaa","1","xxx" "ccc, Inc.","6100","yyy" "bbb","609","zzz"
我希望按第二列排序作为数字,我试过了
sort --field-separator=',' --key=2n
问题是,由于引用了所有值,因此它们无法通过-n(数字)选项正确排序。有解决方案吗?
一个小技巧,它使用双引号作为分隔符:
sort --field-separator='"' --key=4 -n
对于引用的csv
,请使用具有适当csv
解析器的语言。以下是使用perl
的示例。
perl -MText::ParseWords -lne '
chomp;
push @line, [ parse_line(",", 0, $_) ];
}{
@line = sort { $a->[1] <=> $b->[1] } @line;
for (@line) {
local $" = qw(",");
print qq("@$_");
}
' file
输出:
"aaa","1","xxx"
"bbb","609","zzz"
"ccc, Inc.","6100","yyy"
说明:
chomp
函数从输入中删除新行。END
块中,对第二列上的数组数组进行排序,并将其分配给原始数组数组。","
,然后使用前面和后面的"
打印它以创建原始格式的行。将您的示例放入名为sort2.txt的文件中我发现以下内容可以正常工作。
sort -t'"' -k4n sort2.txt
使用以下命令排序(感谢Jonathan的改进)
希望这可以帮助!
没有一个非常简单的解决方案。如果你做出一些合理的假设,那么你可以考虑:
sed 's/","/^A/g' input.csv |
sort -t'^A' -k 2n |
sed 's/^A/","/g
这将","
序列替换为Control-A(在代码中显示为^A
),然后将其用作sort
中的字段分隔符(第2列上的数字排序),然后再次使用","
替换Control-A字符。
如果你使用bash
,你可以使用ANSI C quoting机制$'\1'
将控制字符可视地嵌入到脚本中;你只需要在转义之前完成单引号字符串,然后重启它:
sed 's/","/'$'\1''/g' input.csv |
sort -t$'^A' -k 2n |
sed 's/'$'\1''/","/g
或者使用双引号而不是单引号,但由于您要替换的双引号,这会变得混乱。但你可以简单地逐字输入字符,像vim
这样的编辑会乐意向你展示。
有时,只有在必要时才会引用CSV文件中的值。在这种情况下,使用"
作为分隔符是不可靠的。
例:
"Forest fruits",198
Apples,456
bananas,67
使用awk
,sort
和cut
,您可以在第一列中对原始文件进行排序:
awk -F',' '{
a = $1; # or the column index you want
gsub(/(^"|"$)/, "", a);
print a","$0
}' file.csv | sort -k1 | cut -d',' -f1 --complement
这将使您想要在前面排序的列没有引号,然后按照您想要的方式对其进行排序,并在最后删除此列。