簡體   English   中英

使用bash腳本計算json的累計時間

[英]Calculate accumulated times from json with bash script

我有json格式的數據,用事件(輸入/輸出)記錄時間戳(24h格式的hh:mm)。 我的目標是將“IN”事件和下一個“OUT”事件之間的所有時間差異相加。

為簡化起見,我假設沒有不一致(第一個元素總是“IN”,每個“IN”后面跟一個“OUT”)。 例外:如果最后一個元素是“IN”,則必須在當前時間和最后一個“IN”事件的時間戳之間進行計算。

這是我的腳本到目前為止,它計算所有的時間跨度,也在OUT和IN事件之間。 但我只需要介於IN和OUT事件之間的那些。

歡迎任何可能更有用的提示!

#!/bin/bash

JSON='{ "times": [ [ "7:43", "IN" ], [ "8:26", "OUT" ], [ "8:27", "IN" ], [ "9:12", "OUT" ], [ "9:14", "IN" ], [ "9:22", "OUT" ], [ "9:23", "IN " ], [ "12:12", "OUT" ], [ "13:12", "IN" ] ]}'
IN_TIMES=$(jq '.times | to_entries | .[] | select(.value[1]| tostring | contains("IN")) | .value[0]' <<< "$JSON")
OUT_TIMES=$(jq '.times | to_entries | .[] | select(.value[1]| tostring | contains("OUT")) | .value[0]' <<< "$JSON")
ALL_TIMES=$(jq -r '.times| to_entries | .[] | .value[0]' <<< "$JSON")

prevtime=0
count=0
for i in $(echo $ALL_TIMES | sed "s/ / /g")
do
    if [[ "$count" -eq 0 ]]; then
     (( count++ ))
     prevtime=$i
     continue
    else
     (( count++ ))
    fi

    time1=`date +%s -d ${prevtime}`
    time2=`date +%s -d ${i}`
    diffsec=`expr ${time2} - ${time1}`

    echo From $prevtime to $i: `date +%H:%M -ud @${diffsec}`
    prevtime=$i

done

這是一個只能調用jq一次的jq解決方案。 但請注意,可能需要調整以考慮時區考慮因素,錯誤處理以及可能的其他復雜情況:

def mins: split(":") | map(tonumber) | .[0] * 60 + .[1];

def diff: (.[1] - .[0]) | if . >= 0 then . else 24*60 + . end;

def now_mins: now | gmtime | .[3] * 60 + .[4];

def pairs:
  range(0; length; 2) as $i | [.[$i], .[$i+1] ];

def sigma(s): reduce s as $s (0; . + $s);

.times
| map( .[0] |= mins )
| if .[-1][1] == "IN" then . + [ [now_mins, "OUT"] ] else . end
| sigma(pairs | map(.[0]) | diff)

由於您可以測量最新的時間,因此計算分鍾數就足夠了,而不會弄亂命令date 我有一個awk解決方案:

awk -F: -vIRS=" " -vfmt="From %5s to %5s: %4u minutes\n" \
  '{this=$1*60+$2}a{printf(fmt,at,$0,this-a);a=0;next}{a=this;at=$0}\
  END{if(a){$0=strftime("%H:%M");printf(fmt,at,$0,$1*60+$2-a)}}' <<<"$ALL_TIMES"

它的工作原理是將冒號定義為字段分隔符,將空格定義為記錄分隔符。 通過這種方式,我們每次都會獲得一個包含兩個字段的單獨記錄。 然后

  • {this=$1*60+$2} :我們計算當前記錄中有多少分鍾並將它們放入變量this
  • a{printf(fmt,at,$0,this-a);a=0;next} :如果(最初為空)變量a不為null也不為零,我們正在讀取OUT條目,因此我們打印出我們想要的內容,設置a零,因為下一場將是一個IN輸入,我們將繼續到下一個記錄。
  • {a=this;at=$0}否則,我們正在閱讀的IN條目,並設置a其分鍾,並at它的字符串表示(需要我們將打印它,按照前文的情況下)。
  • END{if(a){$0=strftime("%H:%M");printf(fmt,at,$0,$1*60+$2-a)}} :最后,如果我們還有一些懸空IN數據,我們將$0設置$0格式正確的當前時間並打印我們想要的內容。

全部做完。

使用Xidel和一點XQuery魔術,這很簡單:

#!/bin/bash

JSON='{"times": [["7:43", "IN"], ["8:26", "OUT"], ["8:27", "IN"], ["9:12", "OUT"], ["9:14", "IN"], ["9:22", "OUT"], ["9:23", "IN "], ["12:12", "OUT"], ["13:12", "IN"]]}'

xidel -s - --xquery '
  let $in:=$json/(times)()[contains(.,"IN")](1) ! time(
        substring(
          "00:00:00",
          1,
          8-string-length(.)
        )||.
      ),
      $out:=$json/(times)()[contains(.,"OUT")](1) ! time(
        substring(
          "00:00:00",
          1,
          8-string-length(.)
        )||.
      )
  for $x at $i in $out return
  concat(
    "From ",
    $in[$i],
    " to ",
    $x,
    ": ",
    $x - $in[$i] + time("00:00:00")
  )
' <<< "$JSON"

$in

00:07:43
00:08:27
00:09:14
00:09:23
00:13:12

$out

00:08:26
00:09:12
00:09:22
00:12:12

輸出:

From 00:07:43 to 00:08:26: 00:00:43
From 00:08:27 to 00:09:12: 00:00:45
From 00:09:14 to 00:09:22: 00:00:08
From 00:09:23 to 00:12:12: 00:02:49

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM