我有一个采用这种格式的 .csv 文件;
myfile.csv
**Date,Timestamp,Data1,Data2,Data3,Data4,Data5,Data6**
20130730,22:08:51.244,APPLES,Spain,67p,blah,blah
20130730,22:08:51.244,PEARS,Spain,32p,blah,blah
20130730,22:08:51.708,APPLES,France,102p,blah,blah
20130730,22:10:62.108,APPLES,Spain,67p,blah,blah
20130730,22:10:68.244,APPLES,Spain,67p,blah,blah
我希望输入一个时间戳,该时间戳很可能与文件中的毫秒不完全匹配,并找到与特定 grep 搜索匹配的前一行。
所以例如类似的东西;
cat myfile.csv | grep 'Spain' | grep 'APPLES' | grep -B1 "22:09"
应该返回
20130730,22:08:51.244,APPLES,Spain,67p,blah,blah
但到目前为止,我只能让它在 grep 中使用精确的时间戳。有没有办法让它将这些视为时间序列? (我猜这就是问题所在 - 它正在尝试纯粹的模式匹配,而不是无理地未能找到一个)
最佳答案
我还有一个使用 awk 的奇特解决方案:
awk -F ',' -v mytime="2013 07 30 22 09 00" '
BEGIN {tlimit=mktime(mytime); lastline=""}
{
l_y=substr($1,0,4); l_m=substr($1,4,2); l_d=substr($1,6,2);
split($2,l_hms,":"); l_hms[3]=int(l_hms[3]);
line_time=mktime(sprintf("%d %d %d %d %d %d", l_y, l_m, l_d, l_hms[1], l_hms[2], l_hms[3]));
if (line_time>tlimit) exit; lastline=$0;
}
END{if lastline=="" print $0; else print lastline;}' myfile.csv
它的工作原理是使用 awk 的时间函数 mktime
从每一行生成时间戳。 。我还假设 $1
是日期。
在第一行,您必须提供所需时间限制的时间戳(此处我选择2013 07 30 22 09 00
)。您必须按照 mktime
使用的格式编写它:YYYY MM DD hh mm ss
。您以构成时间限制的时间戳开始 awk 语句。然后,对于每一行,您可以从 $1
(第 4 行)获取年、月和日,然后从 $2
(第 5 行)获取确切的小时。由于 mktime
仅需要整秒,因此我截断了秒数(您可以使用 int(l_hms[3]+0.5)
将其四舍五入)。在这里,您可以执行任何您想要近似时间戳的操作,例如丢弃秒数。在第 6 行,我根据提取的六个日期字段制作了时间戳。最后,在第 7 行,我比较时间戳并在达到时间限制时转到结束。正如您想要的前一行,我将该行存储到变量 laSTLine
中。退出时,我打印 laSTLine
;如果达到第一行的时间限制,我会打印第一行。
此解决方案适用于您的示例文件,并且适用于您提供的任何日期。您只需以正确的格式提供日期限制即可!
编辑
我意识到mktime
是没有必要的。如果假设 $1
是写为 YYYYMMDD 的日期,则可以将日期作为数字进行比较,然后与时间进行比较(使用 split
提取,按照其他答案中的方式重新构建为数字)。在这种情况下,您可以按照所需的格式提供时间限制,并在 BEGIN
block 中恢复正确的日期和时间限制。
关于Bash 查找时间戳之前的最后一个条目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18404564/