[英]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.