使用Linux根据最小/最大值过滤一个非常大的、数字排序的CSV文件?

使用Linux根据最小/最大值过滤一个非常大的、数字排序的CSV文件?,linux,bash,csv,awk,sed,Linux,Bash,Csv,Awk,Sed,我试图输出一个CSV文件的行,它相当大。在过去,我尝试过不同的方法,最终发现Linux的命令行界面(sed、awk、grep等)是处理这些类型文件的最快方法 我有一个如下的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

我试图输出一个CSV文件的行,它相当大。在过去,我尝试过不同的方法,最终发现Linux的命令行界面(sed、awk、grep等)是处理这些类型文件的最快方法

我有一个如下的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
sed '/^1000,/,/^1400,/!d' infile.csv
虽然第一列在数字上不断增加,但每个数字之间的间距随机变化。我需要能够输出第一列中值在X和Y之间的所有行

比如:

sed ./csv -min --col1 1000 -max --col1 1400
它将输出第一列值在1000和1400之间的所有行

行之间的差异足够大,以至于在一个大于5 GB的文件中,可能只有~5个重复项,因此,如果只计算一次重复项,这不会有什么大不了的,但是如果它由于重复行而抛出错误,那将是一件大不了的事


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

如果您知道数字是递增的且唯一的,则可以使用如下地址:

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
sed '/^1000,/,/^1400,/!d' infile.csv
它不会打印与
/^1000,/
匹配的行和与
/^1400,/
匹配的行之间的行之外的任何行

请注意,如果
1000
1400
实际上不作为值存在,则这不起作用,即在这种情况下,它根本不会打印任何内容


在任何情况下,正如mklement0和另一个人的答案所示,awk是这里更好的选择。

您可以使用
awk
轻松完成此操作,尽管它不会充分利用正在排序的文件:

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

当涉及到大文件时,优化很重要;以下
awk
命令:

  • 参数化(使用变量定义范围边界)
  • 仅对范围之前的记录执行一次比较
  • 找到感兴趣的最后一条记录后立即退出
awk-F,-v from=1000-v to=1400'$1to{exit}1./csv

因为
awk
执行数值比较(输入字段看起来像数字),所以范围边界不需要精确匹配字段值。

下面是一个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"
#/bin/bash
fname=“$1”
开始编号=“2美元”
end_nr=“$3”
当IFS=,read-r nr rest | |[[-n$nr&&n$rest]];做
如果($nr<$start_nr));然后继续;
elif(($nr>$end_nr));然后打破;fi
printf“%s,%s\n”“$nr”“$rest”
完成<“$fname”
然后您可以将其称为
script.sh foo.csv 1000 2000


当数字足够大时,脚本将开始打印,当数字超过限制时,脚本将立即停止。

我喜欢@Benjamin W.answer。哦,我们能利用“0”吗
sed'^1[[:num:]{3},/,/^14[[:num:]{3}/p'
,即使现有的1000和1400实际上没有出现,它也可以工作。起始值为1000到1999之间的任何数字,结束值为1400到1499之间的任何行都足够了。这当然需要一些正则表达式的知识来调用脚本…谢谢。行是唯一的,但第一列的值可能不唯一。真正的问题是您描述的失败状态,其中可能不存在1000和1400。除非范围从文件开头附近开始,并且很小,否则如果输入量很大,速度会非常慢。顺便说一句:一般来说是这样的。