shell 获取两大文件的交集


两个文件格式上是一样的,一行一串数字。文件行上也许都不是唯一的。

求出这两个文件的交集,结果应该是唯一的,而且是既在一文件中有的也在二文件中有的。

一个文件在八十万行左右,另一个文件可能过三千万以上。


awk 'NR==FNR{a[$1]=1}NR>FNR&&a[$1]{delete a[$1]; print}' 八十万file1 三千万file2

但是这样有个问题,会无缘无故对第二个文件产生大量的无用的a[]数组元素

Areference to an array element that has no recorded value yields a value of "", the null string.
This includes elements that have not been assigned any value as well as elements that have be deleted.
Such a reference automatically creates that array element,with the null string as its value. (In some
cases, this is unfortunate, because it might waste memory inside awk.)

用$1 in a 来改进 a[$1] (NR>FNR&&a[$1] 会给a添加新的项)

awk 'NR==FNR{a[$1]=1}NR>FNR&&($1 in a)' file1 file2

为了去除同一个文件中重复,还应该删掉已经输出过的a[]数组元素

awk 'NR==FNR{a[$1]=1}NR>FNR&&($1 in a){delete a[$1]; print}' file1 file2

附加解释:
NR:已经读取的文件行(纪录)的数量
FNR:本文件中已经读取的文件行(纪录)的数量
NR==FNR, 一般表示是所有第一个文件的纪录
NR>FNR,就是第二个文件的纪录

PS: Solaris 上awk跟linux上GNU的awk不一样,建议Solaris上用nawk代替awk ....

一些例子:

QUOTE:
1、用某一文件的一个域替换另一个文件中的的特定域?
http://bbs.chinaunix.net/forum/viewtopic.php?t=500015
文件passwd:
s2002408030068:x:527:527::/home/dz02/s2002408030068:/bin/pw
s2002408032819:x:528:528::/home/dz02/s2002408032819:/bin/pw
s2002408032823:x:529:529::/home/dz02/s2002408032823:/bin/pw
文件shadow:
s2002408030068:$1$d8NwFclG$v4ZTacfR2nsbC8BnVd3dn1:12676:0:99999:7:::
s2002408032819:$1$UAvNbHza$481Arvk1FmixCP6ZBDWHh0:12676:0:99999:7:::
s2002408032823:$1$U2eJ3oO1$bG.eKO8Zupe0TnyFhWX9Y.:12676:0:99999:7:::
用shadow文件中的密文部分替换passwd中的"x",生一个新passwd文件,如下所示
s2002408030068:$1$d8NwFclG$v4ZTacfR2nsbC8BnVd3dn1:527:527::/home/dz02/s2002408030068:/bin/pw
s2002408032819:$1$UAvNbHza$481Arvk1FmixCP6ZBDWHh0:528:528::/home/dz02/s2002408032819:/bin/pw
s2002408032823:$1$U2eJ3oO1$bG.eKO8Zupe0TnyFhWX9Y.:529:529::/home/dz02/s2002408032823:/bin/pw

CODE:
awk 'BEGIN{OFS=FS=":"} NR==FNR{a[$1]=$2}NR>FNR{$2=a[$1];print}' shadow passwd
NR==FNR,第一个文件shadow,以$1为下标,将$2的值赋给数组a
NR>FNR,第二个文件passwd,将文件shadow$2的值赋值给文件passwd
 

QUOTE:
2、
cat file1:
0011AAA 200.00 20050321
0012BBB 300.00 20050621
0013DDD 400.00 20050622
0014FFF 500.00 20050401
cat file2:
I0011  11111
I0012  22222
I0014  55555
I0013  66666
规则:比较 file1的1-4字符 和 file2的2-5 字符,如果相同,将file2 的第二列 与 file1 合并 file3
0011AAA 200.00 20050321 11111
0012BBB 300.00 20050621 22222
0013DDD 400.00 20050622 66666
0014FFF 500.00 20050401 55555
 

CODE:
awk  'NR==FNR{a[substr($1,2,5)]=$2}NR>FNR&&a[b=substr($1,1,4)]{print $0, a[b]}' file2 file1 >file3
 
 

QUOTE:
3、如果文件a中包含文件b,则将文件b的记录打印出来
http://bbs.chinaunix.net/forum/viewtopic.php?t=520411
文件a:
10/05766798607,11/20050325191329,29/0.1,14/05766798607
10/05767158557,11/20050325191329,29/0.08,14/05767158557
文件b:
05766798607
05766798608
05766798609
通过文件a和文件b对比,导出这样的文件出来.
10/05766798607,11/20050325191329,29/0.1,14/05766798607
a

CODE:
awk -F'[/,]' 'ARGIND==1{a[$0]}ARGIND>1{($2 in a);print $0}' b a
awk -F'[/,]' 'NR==FNR{a[$0]}NR>FNR{($2 in a);print $0}' b a
 

QUOTE:
4、
file1文件内容
   1     0.5  100
                                 10  15    36.5
file2文件
        50   10    9
                                 3.2   1     5
将两个文件合成一个文件如:
   51     10.5    109
                                                              13.2   16      41.5
就是对应的字段进行相加以后的数字。

CODE:
awk '{for (i=1;i<=NF;i++) a[i]=$i;getline <"file2";for (i=1;i<NF;i++) printf $i+a[i]" ";printf $NF+a[NF] "\n"}' file1
 
 

QUOTE:
5、
文件a
1000 北京市 地级 北京市 北京市
1100 天津市 地级 天津市 天津市
1210 石家庄市 地级 石家庄市 河北省
1210 晋州市 县级 石家庄市 河北省
1243 滦县 县级 唐山市 河北省
1244 滦南县 县级 唐山市 河北省
b文件:
110000,北京市
120000,天津市
130000,河北省
130131,平山县
130132,元氏县
这样的字段
a中第二列在b中可能有可能没有,需要把有的匹配起来生成新的一列:要包含a和b的第一列。没有匹配的按照b原来的格式进行输出。
 

CODE:
awk 'BEGIN{FS="[ |,]";OFS=","}NR<=FNR{a[$2]=$1}NR>FNR{print $1,$2,a[$2]}' a b
 
 

QUOTE:
6、
file1的第一列与file2的第3列相同,
file1的第二列与file2的第4列的3-5位相同,
file1的第三列与file2的最后一列相同,
# cat file1
AAA  001  1000.00
BBB  001  2000.00
DDD  002  4000.00
EEE  002  5000.00
FFF  003  6000.00
# cat file2
01 1111  AAA  WW001  $$  1000.00
02 2222  BBB  GG001  %%%%  2000.00
03 3333  CCC  JJ001  ****  3000.00
04 4444  DDD  FF002  &&&&  4000.00
05 5555  EEE  RR002  @@@@  5000.00
06 666   FFF  UU003  JJJJ  6000.00
07 777   III  II005  PPPP  7000.00
08 8888  TTT  TT008  TTTT  8000.00
 

CODE:
# awk 'NR<=FNR{a[$1]=$1"x"$2"x"$3}
> NR>FNR{b=substr($4,3);c=$3"x"b"x"$6;if(c==a[$3]) print}' file1 file2
01 1111  AAA  WW001  $$  1000.00
02 2222  BBB  GG001  %%%%  2000.00
04 4444  DDD  FF002  &&&&  4000.00
05 5555  EEE  RR002  @@@@  5000.00
06 666   FFF  UU003  JJJJ  6000.00



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值