2017-04-10 43 views
2

我想输出一个很大的CSV文件的行。在过去,我尝试了不同的东西,最终发现Linux的命令行界面(sed,awk,grep等)是处理这些类型文件的最快方式。使用Linux根据最小/最大值筛选非常大的数字排序的CSV文件?

我有一个CSV文件是这样的:

1,rand1,rand2 
4,randx,randy, 
6,randz,randq, 
... 
1001,randy,randi, 
1030,rando,randn, 
1030,randz,randc, 
1036,randp,randu 
... 
1230994,randm,randn, 
1230995,randz,randl, 
1231869,rande,randf 

虽然第一列数值的增加,每个数字之间的空间随机变化。我需要能够输出在第一列中具有X和Y之间的值的所有行。

喜欢的东西:

sed ./csv -min --col1 1000 -max --col1 1400 

这将输出所有具有在1000和1400

的路线之间的第一列值的线是足够不同的是,在A> 5 GB的文件有可能只要重复5次,所以如果只计算一次重复次数就不会有什么大不了的 - 但如果由于重复行而引发错误,这将是一件大事。

我可能不知道是否存在特定的线条值(例如1000是粗略估计值,不应该假定为第一列值)。

+0

我喜欢@Benjamin W.回答。 OP,我们可以利用“0”吗? 'sed'^ 1 [[:num:]] {3},/,/^14 [[:num:]] {3}/p''即使现有的1000和1400实际上没有发生, 1000到1999之间的任何数字以及1400到1499之间的任何数字结束就足够了。这当然需要一些正则表达式知识来调用脚本... – Yunnosch

回答

5

优化事,当谈到大型文件;下面awk命令:

  • 被参数(使用变量来定义的范围的边界)
  • 执行仅针对范围之前来记录一个单一的比较。
  • 只要找到最后一条记录,就立即退出。
awk -F, -v from=1000 -v to=1400 '$1 < from { next } $1 > to { exit } 1' ./csv 

由于awk执行数值比较(其中,像数字输入字段),该范围的边界不必精确地匹配字段值。

0

如果您知道的数量正在增加,独特的,你可以使用的地址是这样的:

sed '/^1000,/,/^1400,/!d' infile.csv 

这确实打印任何行是匹配/^1000,/和一个之间的界线之外与/^1400,/匹配的那个。

请注意,如果10001400实际上并不作为值存在,即在此情况下根本不打印任何内容,则不起作用。

无论如何,正如mklement0和其他人的回答所证明的,awk在这里是更好的选择。

+1

谢谢。这些行是唯一的,但第一列值可能不是。真正的问题是你描述的失败状态,1000和1400可能不存在。 –

0

您可以轻松地awk做到这一点,虽然它不会充分利用的文件进行排序:

awk -F , '$1 > 1400 { exit(0); } $1 >= 1000 { print }' file.csv 
0

下面是脚本的bash的版本:

#! /bin/bash 
fname="$1" 
start_nr="$2" 
end_nr="$3" 
while IFS=, read -r nr rest || [[ -n $nr && -n $rest ]]; do 
    if (($nr < $start_nr)); then continue; 
    elif (($nr > $end_nr)); then break; fi 
    printf "%s,%s\n" "$nr" "$rest" 
done < "$fname" 

,你会再打电话script.sh foo.csv 1000 2000

当数量足够大,然后立即停止该脚本将开始打印时,上面的数字变极限。

+1

除非范围在文件开头附近开始,并且很小,否则在输入较大的情况下,速度会非常慢。顺便说一句:它通常[最好不要'$' - 在Bash中的算术上下文中的前缀变量引用](http://stackoverflow.com/a/43312237/45375)。 – mklement0