我在一个文件中有以下时间戳可能会持续24小时或更多:
2014-11-11-04.01.05.000000
2014-11-11-04.03.33.000000
2014-11-11-04.06.02.000000
2014-11-11-04.08.31.000000
每个时间戳之间的间隙应小于5分钟。如何将一个简单的bash shell脚本放在一起解析文件并告诉我是否有超过5分钟的间隙?我看到的最简单的方法是用前一行减去下一行。但我对bash shell脚本并不是很好。有人可以帮忙吗?
答案 0 :(得分:4)
这使用GNU date
来解释时间。下面的代码从名为file
的文件中读取,并循环遍历每一行,检查是否存在超过300秒的时间间隔:
while read newline
do
new=$(date -d "$(echo "$newline" | sed -E 's/-([0-9][0-9])\.([0-9][0-9])\./ \1:\2:/')" '+%s')
if [ "$old" ] && (( $new - $old > 300))
then
printf "%4i seconds gap before %s" "$((new - old))" "$newline"
fi
old=$new
done <file
让我们考虑一下这个测试文件:
$ cat file
2014-11-11-04.01.05.000000
2014-11-11-04.03.33.000000
2014-11-11-04.08.31.000000
2014-11-11-04.13.32.000000
2014-11-11-05.13.33.000000
以上脚本发现超过5分钟的两个差距:
301 seconds gap before 2014-11-11-04.13.32.000000
3601 seconds gap before 2014-11-11-05.13.33.000000
观察到这可以检测到小至5分钟和1秒的间隙。即使分钟没有变化,它也可以检测到1小时的差距。
为了理解其所有潜在复杂性的时间格式,GNU date
实用程序用于将时间转换为秒 - 自 - 纪元。这简单地完成:
$ date -d '2014-11-11 04:01:05.000000' '+%s'
1415707265
我的date
(较新版本可能不同)不支持我们输入的确切格式:
$ date -d '2014-11-11-04.01.05.000000' '+%s'
date: invalid date `2014-11-11-04.01.05.000000'
但是,我们可以使用sed
使格式看起来像上面的格式:
$ date -d "$(echo "$newline" | sed -E 's/-([0-9][0-9])\.([0-9][0-9])\./ \1:\2:/')" '+%s'
1416384000
接下来,将这些秒数转换为shell变量是一个问题。为此,使用命令替换:
new=$(date -d "$(echo "$newline" | sed -E 's/-([0-9][0-9])\.([0-9][0-9])\./ \1:\2:/')" '+%s')
使用变量new
中的最近时间,我们可以看到自上次以来是否已超过5分钟(300秒)(存储在变量old
中),如果是, ,打印出一条消息:
if [ "$old" ] && (( $new - $old > 300))
then
printf "%4i seconds gap before %s\n" "$((new - old))" "$newline"
fi
上面的第一个测试[ "$old" ]
确保已定义变量old
。它将始终被定义,除了我们读入的第一行。因此,测试[ "$old" ]
的效果是跳过第一行。
第二项测试是(( $new - $old > 300))
。这只是确定自上一行以来是否已超过300秒。
sed
不支持-E
对于GNU sed
,-E
表示扩展的正则表达式格式。在Mac OSX上,将使用-r
代替它。如果您使用的是不支持-E
的旧Linux系统,我们可以尝试使用基本的正则表达式语法。尝试:
$ echo 2014-11-11-04.01.05.000000 | sed 's/-\([0-9][0-9]\)\.\([0-9][0-9]\)\./ \1:\2:/'
2014-11-11 04:01:05.000000
和
$ date -d "$(echo 2014-11-11-04.01.05.000000 | sed 's/-\([0-9][0-9]\)\.\([0-9][0-9]\)\./ \1:\2:/')" '+%s'
1415707265
正如您所看到的,基本正则表达式和扩展正则表达式之间的区别在于必须转义哪些字符。
如果可行,请使用:
while read newline
do
new=$(date -d "$(echo "$newline" | sed 's/-\([0-9][0-9]\)\.\([0-9][0-9]\)\./ \1:\2:/')" '+%s')
if [ "$old" ] && (( $new - $old > 300))
then
printf "%4i seconds gap before %s" "$((new - old))" "$newline"
fi
old=$new
done <file
答案 1 :(得分:1)
使用GNU awk,它具有内置时间功能:
gawk '
{
split($1, a, /[-.]/)
t = mktime(a[1] " " a[2] " " a[3] " " a[4] " " a[5] " " a[6])
}
NR > 1 && t - prev > 300 {print NR, $0}
{prev = t}
' <<END
2014-11-11-04.01.05.000000
2014-11-11-04.03.33.000000
2014-11-11-04.06.02.000000
2014-11-11-04.08.31.000000
2014-11-11-04.15.12.0
END
5 2014-11-11-04.15.12.0