Bash脚本根据另一个文件中指定的日期从日志文件中提取条目?

时间:2010-09-02 21:29:16

标签: bash file awk extract

我有一个非常大的逗号分隔的CSV日志文件(> 50000行,我们称之为file1.csv)看起来像这样:

field1,field2,MM-DD-YY HH:MM:SS,field4,field5...
...
field1,field2,07-29-10 08:04:22.7,field4,field5...
field1,field2,07-29-10 08:04:24.7,field4,field5...
field1,field2,07-29-10 08:04:26.7,field4,field5...
field1,field2,07-29-10 08:04:28.7,field4,field5...
field1,field2,07-29-10 08:04:30.7,field4,field5...
...

如您所见,中间有一个时间戳字段。

我还有一个文件(我们称之为file2.csv),它有一个简短的列表:

timestamp,YYYY,MM,DD,HH,MM,SS
20100729180031,2010,07,29,18,00,31
20100729180039,2010,07,29,18,00,39
20100729180048,2010,07,29,18,00,48
20100729180056,2010,07,29,18,00,56
20100729180106,2010,07,29,18,01,06
20100729180115,2010,07,29,18,01,15

我想要做的是只提取file1.csv中有时间在file2.csv中指定的行。

如何使用bash脚本执行此操作?由于file1.csv非常大,效率也是一个问题。我以前做过非常简单的bash脚本,但实际上不知道如何处理这个问题。也许是awk的一些实现?或者还有另一种方式吗?

P.S。并发症1:我手动检查了两个文件中的一些条目以确保它们匹配,并且它们确实匹配。只需要一种方法来删除(或忽略)file1.csv中秒(“SS”)字段末尾的额外“.7”。

P.P.S。并发症2:将list1.csv中的条目分开大约两秒钟。有时list2.csv中的时间戳正好位于list1.csv中的两个条目之间!在这种情况下,有没有办法找到最接近的匹配?

3 个答案:

答案 0 :(得分:2)

利用John的答案,您可以对文件进行排序和连接,只打印您想要的列(如果是这样,则打印所有列)。请看下面的内容(请注意,我正在考虑您使用的是UNIX,比如Solaris,因此nawk可能比awk更快,而且我们也没有能够提供更多功能的gawk):

# John's nice code
awk -F, '! /timestamp/ {print $3 "-" $4 "-" ($2-2000) " " $5 ":" $6 ":" $7}' file2.csv > times.list
# Sorting times.list file to prepare for the join
sort times.list -o times.list
# Sorting file1.csv
sort -t, -k3,3 file1.csv -o file1.csv
# Finally joining files and printing the rows that match the times
join -t, -1 3 -2 1 -o 1.1 1.2 1.3 1.4 1.5......1.50 file1.csv times.list 

此方法的一个特殊之处在于您可以更改它以便在几种不同的情况下工作,例如使用不同的列顺序,以及在不连接键列的情况下。使用grep(使用regexp或不使用)

来执行此操作非常困难

答案 1 :(得分:1)

一种方法是使用awk将file2.csv中的时间戳转换为file1.csv的格式,然后使用grep -f搜索file1.csv。这应该非常快,因为它只会通过file1.csv。

awk -F, '! /timestamp/ {print $3 "-" $4 "-" ($2-2000) " " $5 ":" $6 ":" $7}' file2.csv > times.list
grep -f times.list file1.csv

如果您愿意,可以将所有这些组合成一行:

grep -f <(awk -F, '! /timestamp/ {print $3 "-" $4 "-" ($2-2000) " " $5 ":" $6 ":" $7}' file2.csv) file1.csv

答案 2 :(得分:1)

如果你有GNU awk(gawk),你可以使用这种技术。

为了匹配最近的时间,一种方法是让awk在file2.csv中为每一行打印两行,然后在John Kugelman's answer中使用grep -f。第二行将添加一秒。

awk -F, 'NR>1 {$1=""; print strftime("%m-%d-%y %H:%M:%S", mktime($0));
                               print strftime("%m-%d-%y %H:%M:%S", mktime($0) + 1)}' file2.csv > times.list
grep -f times.list file1.csv

这说明了几种不同的技术。

  • 跳过第一个记录跳过标题(使用匹配实际上更好)
  • 而不是单独处理每个字段,$1已清空,strftime以所需格式创建输出
  • mktime将格式为“yyyy mm dd hh mm ss”的字符串(-F,$1的分配删除逗号)转换为自纪元以来的秒数,我们为第二行添加1