awk 处理多个文件
awk 处理多个文件
awk处理多个文件的方式是:一个一个的处理。
Demo1
$ cat 1.txt
a 1
b 2
c 3
d 4
$ cat 2.txt
b 5
c 6
d 7
e 8
$ awk '{print $0}' 1.txt 2.txt
a 1
b 2
c 3
d 4
b 5
c 6
d 7
e 8
那怎么分辨当前处理的是哪一个文件呢?先看一下awk的内建变量有哪些。
FILENAME: 当前输入的文件名字
FNR: 当前输入文件的记录数
NR: awk开始工作处理的总的记录数
NF: 当前记录的字段数
FS: 输入字段分割符
OFS: 输出字段分隔符
RS: 输入记录分隔符
ORS: 输出记录分隔符
ARGIND: 当前处理参数的标志,对于Demo1中的 1.txt 该值是1,2.txt是2
ARGV: 命令行参数数组,对于Demo1是,ARGV[1]="1.txt" ARGV[2]="2.txt"
ARGC: 命令行参数的个数
对于两个文件的时候,我们可以这么处理:
方法1 -- by FNR & NR
由上可知,只有处理第一个文件的时候FNR才会等于NR,所以可以如下所示:
$ awk 'FNR==NR{print $0}FNR!=NR{print $0}' 1.txt 2.txt
$ awk 'FNR==NR{print $0}FNR<NR{print $0}' 1.txt 2.txt
方法2 -- by FILENAME
$ awk 'FILENAME=="1.txt"{print "file1:"$1}FILENAME=="2.txt"{print "file2:" $2}' 1.txt 2.txt
方法3 -- by FILENAME & ARGV
方法2不是很灵活,因为下次换输入的时候,整个命令行都要改一下,很麻烦,其实可以通过ARGV来获取输入的变量名,awk把所有的输入变量都是存放在数组ARGV中。所以可以根据ARGV来获取输入的文件名,提高命令行的灵活性。
$ awk 'FILENAME==ARGV[1]{print "file1:"$1}FILENAME==ARGV[2]{print "file2:" $2}' 1.txt 2.txt
方法4 -- by ARGIND
方法3貌似也有点复杂,可以通过ARGIND来实现。
$ awk 'ARGIND==1{print "file1:"$1}ARGIND==2{print "file2:" $2}' 1.txt 2.txt
上面四个的运行结果都是:
file1:a 1
file1:b 2
file1:c 3
file1:d 4
file2:b 5
file2:c 6
file2:d 7
file2:e 8
对于处理两个以上文件的时候,方法1是不行的,可以用方法2,3,4来实现。
应用举例:
Demo2: 比较两个文件中第一列相同的行,并把文件1中相同的行print
出。 对于Demo1中的文件1,文件2,最后输出:
b 2
c 3
d 4
实现方式:
$ awk 'FNR==NR{a[$1]=$0}FNR!=NR{print a[$1]}' 1.txt 2.txt
先将1.txt做一个字典映射,key是第一列,value是一行,然后取2.txt的第一列为key取字典中的value即可。
Demo3: 借鉴一下别人的例子:比较 file1的1-4字符 和 file2的2-5 字符,如果相同,将file2 的第二列 与 file1 合并 file3(http://bbs.chinaunix.net/thread-577044-1-1.html)
$ 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
$ awk 'NR==FNR{a[substr($1,1,4)]=$0}NR!=FNR&&a[b=substr($1,2,5)]{print a[b] $2}' file1 file2
0011AAA 200.00 20050321 11111
0012BBB 300.00 20050621 22222
0014FFF 500.00 20050401 55555
0013DDD 400.00 20050622 66666
这里主要要注意&&a[b=substr($1,2,5)]
这块,相当于是一个前置条件,即file2的2:5字符如果没有出现就不会执行后面的print语句。
Demo4: 输入下面两个文件
$ cat 1.txt
10/05766798607,11/20050325191329,29/0.1,14/05766798607
10/05767158557,11/20050325191329,29/0.08,14/05767158557
$ cat 2.txt
05766798607
05766798608
05766798609
输出:
10/05766798607,11/20050325191329,29/0.1,14/05766798607
实现方法:
$ awk -F'[/,]' 'NR==FNR{a[$0]=$0}FNR!=NR{if ($2 in a) print $0}' 2.txt 1.txt
$ awk 'BEGIN{FS="[/,]"}NR==FNR{a[$0]}NR!=FNR{if ($2 in a) print $0}' 2.txt 1.txt
前后两个执行的结果是一样的,-F
和 FS
的效果是一样的,都是设置输入分隔符