我有一个这样的文件:
1 Record|1111|ABC
2 text in between for record 1
3 text in between for record 1
4 Record|2222|XYZ
5 text in between for record 2
6 Record|3333|XYZ
7 text in between for record 3
8 .
我想读取这个文件并生成类似的东西
<Record_number> | <start line> | <number of lines> | md5sum(content)
那是:
1111|1|2|md5sum(Record|1111|ABC\ntext in between for record 1\ntext in between for record 1)
2222|4|1|md5sum(Record|2222|XYZ\ntext in between for record 2\n)
ETC。
目前,我正在使用两步过程来执行此操作:
步骤1:
grep -n -C 0 "Record|" ../test.txt | awk -F[':|'] '{print $3"|"$1}'
将创造
1111|1
2222|4
3333|6
第2步: 逐行读取这个文件并通过脚本生成md5sum和行数。
这两个步骤处理的问题是需要更多的处理时间,并且文件大小很大(~4GB)。
有一个更好的方法吗?
答案1
大部分都可以是
awk -F"|" -v OFS="|" '
function md5(lines){
func="printf \"%s\" \""lines"\"|md5sum|cut -f1 -d\ " ;
func | getline v;
return v
}
/Record/{
if(s>0)
print r,l,c,md5(line);
s=1;
r=$2;
c=1;
l=NR;
line=$0
}
!/Record/{
line=line"\n"$0;
c+=1
}
END{
print r,l,c,md5(line);
}' file
简单代码解释:
将字段分隔符(输入和输出)更改为
|
分配
md5
函数(感谢皮埃尔·奥利维尔·瓦雷斯对于想法)计算适当的输入行的 md5sum。 (也许有更好的方法,欢迎您发表评论)对于包含
Record
单词的行,将必要的字段放入变量中,并将计数器中断为 1,并从单词第二次出现开始打印上一个格式化行Record
(对于第二次打印第一次,对于第三次打印第二次,依此类推)。对于没有
Record
单词的行,只需将自己添加到line
变量中,并将 1 添加到计数器中c
完成后打印最后格式化的行(因为最后一行存储在内存中,并且应该在遇到下一个
Record
单词但已到达文件结尾时打印)
答案2
基于科斯塔斯的回答。
1)创建一个文件parse.awk,内容如下:
/^Record/ {
if (s>0) {
printf ("%s|%s|", r,l)
system("echo '"line"' | md5sum - | awk '{print $1}' ");
}
s=1;
r=$2;
c=1;
l=NR;
line="$0";
}
!/^Record/ {
line=line"\n""$0";
c+=1
}
END {
printf ("%s|%s|", r,l)
system("echo '"line"' | md5sum - | awk '{print $1}' ");
}
参见科斯塔斯的解释。该脚本只是执行
printf
结果行的开头(而不是打印,即放置换行符)
system(echo $line | md5sum)
来打印 md5 - 和换行符
2) 运行awk -F"|" -f parse.awk myfile
3)享受结果:
1111|1|cb36533781d8dd00011a85b0db9b87b3
2222|4|521331bb249e8a668afa2199fa8d289a
3333|6|6c2564464187094e9db3159d26ade2a5