寻找时间戳的差距

rcb*_*ted 3 linux bash shell

我在一个可能持续 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 
Run Code Online (Sandbox Code Playgroud)

每个时间戳之间的间隔应小于 5 分钟。如何将一个简单的 bash shell 脚本放在一起来解析文件并告诉我是否有超过 5 分钟的间隔?我看到的最简单的方法是用上一行减去下一行。但我不太擅长 bash shell 脚本。任何人都可以帮忙吗?

Joh*_*024 6

这使用 GNUdate来解释时间。下面的代码从一个名为的文件中读取,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
Run Code Online (Sandbox Code Playgroud)

例子

让我们考虑这个测试文件:

$ 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
Run Code Online (Sandbox Code Playgroud)

上面的脚本找到两个超过 5 分钟的间隔:

 301 seconds gap before 2014-11-11-04.13.32.000000
3601 seconds gap before 2014-11-11-05.13.33.000000
Run Code Online (Sandbox Code Playgroud)

请注意,这可以检测到小至 5 分 1 秒的间隙。即使分钟没有改变,它也会检测到 1 小时的间隔。

这个怎么运作

为了理解时间格式的所有潜在复杂性,GNUdate实用程序用于将时间转换为自纪元以来的秒数。这样做很简单:

$ date -d '2014-11-11 04:01:05.000000' '+%s'
1415707265
Run Code Online (Sandbox Code Playgroud)

我的date(新版本可能会有所不同)不支持我们输入的确切格式:

$ date -d '2014-11-11-04.01.05.000000' '+%s'
date: invalid date `2014-11-11-04.01.05.000000'
Run Code Online (Sandbox Code Playgroud)

但是,我们可以使用sed使格式看起来像上面有效的格式:

$ date -d "$(echo "$newline" | sed -E 's/-([0-9][0-9])\.([0-9][0-9])\./ \1:\2:/')" '+%s'
1416384000
Run Code Online (Sandbox Code Playgroud)

接下来,是将这些秒数放入 shell 变量的问题。为此,使用命令替换:

new=$(date -d "$(echo "$newline" | sed -E 's/-([0-9][0-9])\.([0-9][0-9])\./ \1:\2:/')" '+%s')
Run Code Online (Sandbox Code Playgroud)

使用变量中的最近时间new,我们可以查看自上次(存储在变量中old)以来是否已经过去了 5 分钟(300 秒)以上,如果是,则打印出一条消息:

if [ "$old" ] && (( $new - $old > 300))
then
    printf "%4i seconds gap before %s\n" "$((new - old))" "$newline"
fi
Run Code Online (Sandbox Code Playgroud)

上面的第一个测试[ "$old" ]确保变量old已被定义。除了我们读入的第一行之外,它将始终被定义。因此,测试的效果[ "$old" ]是跳过第一行。

第二个测试是(( $new - $old > 300))。这只是确定自上一行以来是否已经过去了 300 秒以上。

如果您sed不支持怎么办-E

对于 GNU sed-E意味着扩展的正则表达式格式。在 Mac OSX 上,-r将在其位置使用。如果您使用的是不支持 的旧 linux 系统-E,我们可以尝试使用基本的正则表达式语法。尝试:

$ 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
Run Code Online (Sandbox Code Playgroud)

和:

$ date -d "$(echo 2014-11-11-04.01.05.000000 | sed  's/-\([0-9][0-9]\)\.\([0-9][0-9]\)\./ \1:\2:/')" '+%s'
1415707265
Run Code Online (Sandbox Code Playgroud)

如您所见,基本正则表达式和扩展正则表达式之间的区别在于必须对哪些字符进行转义。

如果可行,请使用:

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
Run Code Online (Sandbox Code Playgroud)