计算 bash 脚本中两个文件中的日期/时间差异表单条目

计算 bash 脚本中两个文件中的日期/时间差异表单条目

我有两个文件(已开始和已完成),如下所示:

开始文件:

2018-01-30 10:21:41
2018-01-17 12:22:50
2018-06-27 23:09:20
INVALID
INVALID
... for 800 Rows

完成的文件:

2018-01-30 10:23:54
2018-01-17 13:23:45
2018-06-28 06:10:56
INVALID
INVALID
... for 800 rows

我需要创建第三个文件,其中包含 file2 和 file1 每一行的差异结果 - 以获得时间流逝。

新的第三个文件:

00:02:13
01:00:55
07:01:36
INVALID     //Where any instance of invalid in either file remain in the new file.
INVALID

... 800 行

我能够使用此命令手动使其工作,但没有运气循环遍历我的文件:

string1="10:21:41"
string2="10:23:54"
StartDate=$(date -u -d "$string1" +"%s")
FinalDate=$(date -u -d "$string2" +"%s")
date -u -d "0 $FinalDate sec - $StartDate sec" +"%H:%M:%S"

> 00:02:13 

答案1

作为单线

while read -r StartDate  && read -r FinalDate <&3; do if [[ ${StartDate} != "INVALID" && ${FinalDate} != "INVALID" ]]; then diff=$(expr $(date -d "${FinalDate}" +"%s") - $(date -d "${StartDate}" +"%s")); printf '%dd:%dh:%dm:%ds\n' $((${diff}/86400)) $((${diff}%86400/3600)) $((${diff}%3600/60)) $((${diff}%60));else echo INVALID; fi; done < startedfile 3<finishedfile

作为脚本

#!/bin/bash

while read -r StartDate  && read -r FinalDate <&3; do 
    if [[ ${StartDate} != "INVALID" && ${FinalDate} != "INVALID" ]]; then 
        diff=$(expr $(date -d "${FinalDate}" +"%s") - $(date -d "${StartDate}" +"%s")); 
        printf '%dd:%dh:%dm:%ds\n' $((${diff}/86400)) $((${diff}%86400/3600)) $((${diff}%3600/60)) $((${diff}%60));
    else 
        echo INVALID; 
    fi; 
done < startedfile 3<finishedfile

它会给出这样的输出:

0d:0h:2m:13s
0d:1h:0m:55s
INVALID
0d:7h:1m:36s
INVALID
INVALID

然后你可以将其输出到你想要的文件中。


编辑

正如评论中所建议的,这可以通过安装dateutils包和使用datediff命令来简化。

while read -r StartDate  && read -r FinalDate <&3; do if [[ ${StartDate} != "INVALID" && ${FinalDate} != "INVALID" ]]; then datediff "${StartDate}" "${FinalDate}" -f "%dd:%Hh:%Mm:%Ss";else echo INVALID; fi; done < started.txt 3<finished.txt 

在脚本中

#!/bin/bash

while read -r StartDate  && read -r FinalDate <&3; do 
    if [[ ${StartDate} != "INVALID" && ${FinalDate} != "INVALID" ]]; then 
        datediff "${StartDate}" "${FinalDate}" -f "%dd:%Hh:%Mm:%Ss";
    else 
        echo INVALID; 
    fi; 
done < startedfile 3<finishedfile

答案2

我相信我能够使用以下 bash 脚本解决您的问题:

#!/usr/bin/env bash

sfile=/path/to/start
efile=/path/to/end
ofile=/path/to/out
n=0

while read -r line; do
    ((n++))
    if [[ $line == 'INVALID' ]]; then
        echo "INVALID"
        continue
    fi
    start=$(date -u -d "$line" "+%s")
    end=$(date -u -d "$(sed -n "${n}p" "$efile")" "+%s")
    date -u -d "0 $end sec - $start sec" +"%H:%M:%S"
done<"$sfile" >"$ofile"

这将读取起始文件的每一行并将其与结束文件中的匹配行进行比较。如果该行包含“INVALID”,它将回显“INVALID”并跳到循环的下一个迭代。

答案3

使用ddiffGNUdateutilsbash

#!/bin/bash

paste STARTED COMPLETED |
while IFS=$'\t' read start compl; do
    if [ "$start" = "INVALID" ] || [ "$compl" = "INVALID" ]; then
        echo 'INVALID'
    else
        ddiff -f '%0H:%0M:%0S' "$start" "$compl"
    fi
done

假设输入文件被称为STARTEDand COMPLETED,这将创建一个制表符分隔的循环输入while,其中第一个字段中包含开始时间,第二个字段中包含完成时间。它读取这些并检查这两个时间中是否有任何一个是INVALID。如果没有,它就会ddiff与他们通话。

可以将其输出保存到文件中,并done在末尾或调用脚本时在命令行上的脚本名称之后进行重定向。

在提供的数据上运行它:

$ bash script.sh
00:02:13
01:00:55
07:01:36
INVALID
INVALID

答案4

zsh

#! /bin/zsh -
# usage: that-script file1 file2
zmodload zsh/datetime
while
  IFS= read -ru3 a &&
   IFS= read -ru4 b
do
  if
    strftime -rs at '%Y-%m-%d %H:%M:%S' "$a" 2> /dev/null &&
      strftime -rs bt '%Y-%m-%d %H:%M:%S' "$b" 2> /dev/null
  then
    d=$((bt - at))
    printf '%02d:%02d:%02d\n' $((d/3600)) $(((d/60)%60)) $((d%60))
  else
     printf '%s\n' $a
  fi
done 3< ${1?} 4< ${2?}

仍然使用 shell 循环来处理文本这通常被认为是不好的做法但至少在这里我们只使用内置命令,这意味着性能不会像date为每行输入调用两个外部 GNU 命令那样糟糕。

相关内容