1 bash shell comparison awk large-data
我的任务如下 - 我有两个CSV文件:
文件1(~9.000.000记录):
类型(文本),数字,状态(文本),序列号(数字),数据1,数据2,数据3
文件2(~6000条记录): serial_range_start(number),serial_range_end(number),info1(text),info2(text)
目标是在文件1中的每个条目中添加来自文件2的相应info1和info2: 类型(文本),数字,状态(文本),序列(数字),数据1,数据2,数据3,信息1(文本),信息2(文本)
我使用以下脚本:
#!/bin/bash
USER="file1.csv"
RANGE="file2.csv"
for SN in `cat $USER | awk -F , '{print $4}'`
do
#echo \n "$SN"
for LINE in `cat $RANGE`
do
i=`grep $LINE $RANGE| awk -F, '{print $1}'`
#echo \n "i= " "$i"
j=`grep $LINE $RANGE| awk -F, '{print $2}'`
#echo \n "j= " "$j"
k=`echo $SN`
#echo \n "k= " "$k"
if [ $k -ge $i -a $k -le $j ]
then
echo `grep $SN $USER`,`grep $i $RANGE| cut -d',' -f3-4` >> result.csv
break
#else
#echo `grep $SN $USER`,`echo 'N/A','N/A'` >> result.csv
fi
done
done
Run Code Online (Sandbox Code Playgroud)
该脚本在小文件上工作得相当好,但我确信有一种方法可以优化它,因为我在具有4GB RAM的i5笔记本电脑上运行它.我是shell脚本的新手,经过数小时的研究,试验和错误后,我想出了这个脚本,但现在我已经没有想法了.
注意:并非文件1中的所有信息都可以在文件中找到.
谢谢!
阿德里安.
文件示例和其他信息:
文件1示例:
prep,28620026059,Active,123452010988759,No,No,No
post,28619823474,Active,123453458466109,Yes,No,No
post,28619823474,Inactive,123453395270941,Yes,Yes,Yes
Run Code Online (Sandbox Code Playgroud)
文件2示例:
123452010988750,123452010988759,promo32,1.11
123453458466100,123453458466199,promo64,2.22
123450000000000,123450000000010,standard128,3.333
Run Code Online (Sandbox Code Playgroud)
结果示例(当前):
prep,28620026059,Active,123452010988759,No,No,No,promo32,1.11
post,28619823474,Active,123453458466109,Yes,No,No,promo64,2.22
Run Code Online (Sandbox Code Playgroud)
结果示例(很高兴):
prep,28620026059,Active,123452010988759,No,No,No,promo32,1.11
post,28619823474,Active,123453458466109,Yes,No,No,promo64,2.22
post,28619823474,Inactive,123453395270941,Yes,Yes,Yes,NA,NA
Run Code Online (Sandbox Code Playgroud)
在第4列文件2在第一列之后排序之后,文件1被排序.
文件2没有重叠的范围
并非文件1中的所有信息都可以在文件2的范围内找到
再次感谢!
LE:Jonathan提供的脚本似乎在某些记录上存在问题,如下所示:
档案2:
123456780737000,123456780737012,ONE 32,1.11
123456780016000,123456780025999,ONE 64,2.22
Run Code Online (Sandbox Code Playgroud)
档案1:
Postpaid,24987326427,Active,123456780737009,Yes,Yes,Yes
Postpaid,54234564719,Active,123456780017674,Yes,Yes,Yes
Run Code Online (Sandbox Code Playgroud)
输出如下:
Postpaid,24987326427,Active,123456780737009,Yes,Yes,Yes,ONE 32,1.11
Postpaid,54234564719,Active,123456780017674,Yes,Yes,Yes,ONE 32,1.11
Run Code Online (Sandbox Code Playgroud)
它应该是:
Postpaid,24987326427,Active,123456780737009,Yes,Yes,Yes,ONE 32,1.11
Postpaid,54234564719,Active,123456780017674,Yes,Yes,Yes,ONE 64,2.22
Run Code Online (Sandbox Code Playgroud)
它似乎返回0并将信息写在file2的第一条记录上......
我认为这将运作得相当好:
awk -F, 'BEGIN { n = 0; OFS = ","; }
NR==FNR { lo[n] = $1; hi[n] = $2; i1[n] = $3; i2[n] = $4; n++ }
NR!=FNR { for (i = 0; i < n; i++)
{
if ($4 >= lo[i] && $4 <= hi[i])
{
print $1, $2, $3, $4, $5, $6, $7, i1[i], i2[i];
break;
}
}
}' file2 file1
Run Code Online (Sandbox Code Playgroud)
鉴于file2包含:
1,10,xyz,pqr
11,20,abc,def
21,30,ambidextrous,warthog
Run Code Online (Sandbox Code Playgroud)
并file1包含:
A,123,X2,1,data01_1,data01_2,data01_3
A,123,X2,2,data02_1,data02_2,data02_3
A,123,X2,3,data03_1,data03_2,data03_3
A,123,X2,4,data04_1,data04_2,data04_3
A,123,X2,5,data05_1,data05_2,data05_3
A,123,X2,6,data06_1,data06_2,data06_3
A,123,X2,7,data07_1,data07_2,data07_3
A,123,X2,8,data08_1,data08_2,data08_3
A,123,X2,9,data09_1,data09_2,data09_3
A,123,X2,10,data10_1,data10_2,data10_3
A,123,X2,11,data11_1,data11_2,data11_3
A,123,X2,12,data12_1,data12_2,data12_3
A,123,X2,13,data13_1,data13_2,data13_3
A,123,X2,14,data14_1,data14_2,data14_3
A,123,X2,15,data15_1,data15_2,data15_3
A,123,X2,16,data16_1,data16_2,data16_3
A,123,X2,17,data17_1,data17_2,data17_3
A,123,X2,18,data18_1,data18_2,data18_3
A,123,X2,19,data19_1,data19_2,data19_3
A,223,X2,20,data20_1,data20_2,data20_3
A,223,X2,21,data21_1,data21_2,data21_3
A,223,X2,22,data22_1,data22_2,data22_3
A,223,X2,23,data23_1,data23_2,data23_3
A,223,X2,24,data24_1,data24_2,data24_3
A,223,X2,25,data25_1,data25_2,data25_3
A,223,X2,26,data26_1,data26_2,data26_3
A,223,X2,27,data27_1,data27_2,data27_3
A,223,X2,28,data28_1,data28_2,data28_3
A,223,X2,29,data29_1,data29_2,data29_3
Run Code Online (Sandbox Code Playgroud)
该命令的输出是:
A,123,X2,1,data01_1,data01_2,data01_3,xyz,pqr
A,123,X2,2,data02_1,data02_2,data02_3,xyz,pqr
A,123,X2,3,data03_1,data03_2,data03_3,xyz,pqr
A,123,X2,4,data04_1,data04_2,data04_3,xyz,pqr
A,123,X2,5,data05_1,data05_2,data05_3,xyz,pqr
A,123,X2,6,data06_1,data06_2,data06_3,xyz,pqr
A,123,X2,7,data07_1,data07_2,data07_3,xyz,pqr
A,123,X2,8,data08_1,data08_2,data08_3,xyz,pqr
A,123,X2,9,data09_1,data09_2,data09_3,xyz,pqr
A,123,X2,10,data10_1,data10_2,data10_3,xyz,pqr
A,123,X2,11,data11_1,data11_2,data11_3,abc,def
A,123,X2,12,data12_1,data12_2,data12_3,abc,def
A,123,X2,13,data13_1,data13_2,data13_3,abc,def
A,123,X2,14,data14_1,data14_2,data14_3,abc,def
A,123,X2,15,data15_1,data15_2,data15_3,abc,def
A,123,X2,16,data16_1,data16_2,data16_3,abc,def
A,123,X2,17,data17_1,data17_2,data17_3,abc,def
A,123,X2,18,data18_1,data18_2,data18_3,abc,def
A,123,X2,19,data19_1,data19_2,data19_3,abc,def
A,223,X2,20,data20_1,data20_2,data20_3,abc,def
A,223,X2,21,data21_1,data21_2,data21_3,ambidextrous,warthog
A,223,X2,22,data22_1,data22_2,data22_3,ambidextrous,warthog
A,223,X2,23,data23_1,data23_2,data23_3,ambidextrous,warthog
A,223,X2,24,data24_1,data24_2,data24_3,ambidextrous,warthog
A,223,X2,25,data25_1,data25_2,data25_3,ambidextrous,warthog
A,223,X2,26,data26_1,data26_2,data26_3,ambidextrous,warthog
A,223,X2,27,data27_1,data27_2,data27_3,ambidextrous,warthog
A,223,X2,28,data28_1,data28_2,data28_3,ambidextrous,warthog
A,223,X2,29,data29_1,data29_2,data29_3,ambidextrous,warthog
Run Code Online (Sandbox Code Playgroud)
这使用范围列表上的线性搜索; 你可以编写函数,awk二进制搜索寻找正确的范围将在6,000个条目上表现更好.不过,对于读者来说,这部分是一项优化练习.请记住,优化的第一条规则是:不要.优化的第二条规则(仅限专家)是:不要这样做.证明这是一个问题.这段代码不应该花费比复制9,000,000记录文件所需的时间更长的时间(稍微长一点,但不是灾难性的).但请注意,如果file1数据已排序,由于线性搜索,处理的尾部将比起始时间长.如果序列号是随机顺序,那么它们平均需要大约相同的时间.
如果您的CSV数据在文本字段中嵌入了逗号,则 awk不再适用; 你需要一个明确支持CSV格式的工具 - Perl和Python都有合适的模块.
awk -F, 'BEGIN { n = 0; OFS = ","; }
NR==FNR { lo[n] = $1; hi[n] = $2; i1[n] = $3; i2[n] = $4; n++ }
NR!=FNR { i = search($4)
print $1, $2, $3, $4, $5, $6, $7, i1[i], i2[i];
}
function search(i, l, h, m)
{
l = 0; h = n - 1;
while (l <= h)
{
m = int((l + h)/2);
if (i >= lo[m] && i <= hi[m])
return m;
else if (i < lo[m])
h = m - 1;
else
l = m + 1;
}
return 0; # Should not get here
}' file2 file1
Run Code Online (Sandbox Code Playgroud)
编写二进制搜索并不难.这与样本数据上的原始脚本提供相同的结果.它尚未经过详尽的测试,但似乎有效.
请注意,代码并没有真正处理缺少的范围file2; 它假定范围是连续的但不重叠且按排序顺序排列,并涵盖可出现在串行列中的所有值file1.如果这些假设无效,则在修复代码或数据之前会出现不稳定的行为.