次のように、2つのファイル(起動済みと完了済み)があります。
スタートアップファイル:
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の各行の違いの結果を含む3番目のファイルを作成する必要があります。
新しい3番目のファイル:
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
ddiff
GNUを使用しdateutils
て、次の操作を行いますbash
。
#!/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
入力ファイルがSTARTED
andであると仮定すると、最初のフィールドに開始時間があり、2番目のフィールドに終了時間があるタブ区切りのCOMPLETED
ループ入力が生成されます。while
これを読んで、2つの時間のうちの1つが確認されます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?}
それでもシェルループを使ったテキスト処理これは一般的に悪い習慣と見なされます。しかし、少なくともここでは組み込みコマンドのみを使用しています。これはdate
、各入力行に対して2つの外部GNUコマンドを呼び出すのと同じくらいパフォーマンスが悪くないことを意味します。