大文本/ csv文件的比较shell脚本 - 需要改进

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的第一条记录上......

Jon*_*ler 5

我认为这将运作得相当好:

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.如果这些假设无效,则在修复代码或数据之前会出现不稳定的行为.