日付/時刻文字列の比較

日付/時刻文字列の比較

次のデータを含むファイルがあります(サンプルデータのみが表示されます。ファイルには最大2001行が含まれています)。

0001:3002:2018/07/16:12.34.31:ERR 
0002:3002:2018/07/16:12.34.44:ERR 
0003:3002:2018/07/16:12.34.57:ERR 
0004:3002:2018/07/16:12.35.10:ERR 
0005:3002:2018/07/16:12.35.23:ERR 
0006:3002:2018/07/16:12.35.36:ERR 
0007:3002:2018/07/16:12.35.49:ERR 
0008:3002:2018/07/16:12.36.02:ERR 
0009:3002:2018/07/16:12.36.15:ERR

たとえば、2018/07/16:12.36.15のようにbashスクリプトに日付を渡しましょう.このファイルの各行を読み、その行の日付を渡された日付と比較し、渡された日付より大きい日付を持つ行を返したいと思います。

今まで何をしたのか

#!/bin/sh

SEARCH_DATE=$1
errorCodeFilePath=/home/.errorfile.log
lines=`cat $errorCodeFilePath`
for line in $lines; do
   errorCodeDate=$(echo $line |grep -Eo '[[:digit:]]{4}/[[:digit:]]{2}/[[:digit:]]{2}:[[:digit:]]{2}.[[:digit:]]{2}.[[:digit:]]{2}');  
   if [ $errorCodeDate -ge $SEARCH_DATE ];
    then
        echo $errorCodeDate
    fi
done

質問

  1. 日付比較が機能しているかどうかはわかりません。 「整数式エラーが予想されます」というメッセージが表示されます。私は本当に Bash スクリプトを書く方法を知らず、これが私の最初の試みです。

  2. この日付比較を有効にするにはどうすればよいですか?また、日付比較が機能した後は、一致するすべての行の最初と2番目の間の数字を取得する必要があります。

ベストアンサー1

スクリプトはファイル全体を変数として読み込み、その変数の値を繰り返します。これには3つの問題があります。

  1. 最も一般的なケースでは、入力ファイルのサイズがわかりません。これは、場合によっては、変数が次のように大きくなる可能性があることを意味します。非常に大きい。
  2. ループ変数の引用符で囲まれていない値は、シェルを使用して空白(スペース、タブ、および改行)にデータを分割します。データに改行以外のスペースが含まれている場合、ループは誤った操作を実行する可能性があります。
  3. シェルは、ループの前に引用されていない変数の値に対してファイル名のグロービングを実行します。つまり、データに*または同じワイルドカードパターンが含まれている場合、[...]これらのパターンは既存のファイル名と一致します。

この回答は、使用されたタイムスタンプがその後のタイムスタンプが以前のタイムスタンプ(少なくともPOSIXロケールでは)の後にソートされるという点で合理的であるという事実を利用します。

#!/bin/bash

while IFS= read -r line; do
    timestamp=${line%:*}            # Remove ":ERR" at the end
    timestamp=${timestamp#*:*:}     # Remove numbers from start ("0001:3002:")
    if [[ "$timestamp" > "$1" ]]; then
        # According to the current locale, the timestamp in "$timestamp"
        # sorts after the timestamp in "$1".
        printf "Greater: %s\n" "$line"
    fi
done <file

スクリプトは、ファイルと同じ形式のタイムスタンプを唯一の引数として使用します。ファイルの内容を繰り返しfile、各行のタイムスタンプを解析し、それをコマンドラインのタイムスタンプと比較します。>演算子 in を使用した比較は、ファイルbashのタイムスタンプが現在のロケールで指定されたタイムスタンプの後に辞書式でソートされた場合に true になります。比較が真の場合は、ファイルの行を印刷します。

行の終わりと始まりを削除して行のタイムスタンプを解析するための2つの別々の代替方法は、次のように置き換えることができます。

timestamp=$( cut -d ':' -f 3,4 <<<"$line" )

ただし、外部ユーティリティを呼び出すため、実行が遅くなります。

テスト:

$ bash script.sh '2018/07/16:12.36.00'
Greater: 0008:3002:2018/07/16:12.36.02:ERR
Greater: 0009:3002:2018/07/16:12.36.15:ERR

生の行ではなくファイルのタイムスタンプのみを出力するには、コマンドでに変更します"$line""$timestamp"printf

この場合、次のループを実行して作業を高速化することもできます。

#!/bin/bash

cut -d ':' -f 3,4 file |
while IFS= read -r timestamp; do
    if [[ "$timestamp" > "$1" ]]; then
        # According to the current locale, the timestamp in "$timestamp"
        # sorts after the timestamp in "$1".
        printf "Greater: %s\n" "$timestamp"
    fi
done

cutここでは、ファイルから3番目と4番目の分離列(タイムスタンプ)を取得するために使用します:。つまり、元の行を解析する必要はありません。

関連:

おすすめ記事