bashスクリプトを使用してファイルから日付を抽出し、Unixタイムスタンプに変換する方法は?

bashスクリプトを使用してファイルから日付を抽出し、Unixタイムスタンプに変換する方法は?

以下の内容を含むファイルがあります(項目が3つ以上である可能性があります)。

A Version: x_02.28.03.03 000000 aaa 2019/05/21 03:33:04
B Version: x_02.28.03.03 000000 aaa 2019/05/21 03:33:04
C Version: 0.01.011 #3 PREEMPT Tue Apr 4 09:14:17 UTC 2023

unix timestamp今、すべての項目から日付と時刻を抽出したいと思います。つまり、私は、、2019/05/21 03:33:042019/05/21 03:33:04興味があるTue Apr 4 09:14:17 UTC 2023。項目は、後で比較できるように同じ形式でなければなりません。また、位置は固定されません(ただし、行の最後の2つのフィールドになります)。

bash以下はスクリプトの一部です。

#!/bin/bash

ver_file="/home/test/tmp.txt"

ver_c=$(grep -E "C Version:" $ver_file | cut -d" " -f3-)

echo "$ver_c"

誰かがファイルから日付を抽出する方法を教えてもらえますか?

PS:私はWSL2を使用してUbuntuで開発していますが、ターゲットではbusybox date

ベストアンサー1

この説明は実際には質問ではなく、やや混乱しています。でも恋愛はいつも楽しいので助けになってほしいです。

構造化されていない日付を抽出する方法は、ソースによって異なります。文書の日付は悪名高いです。与えられた例で私が見ることができる唯一の一貫性は、日付文字列が行の終わりにあり、すべて列6から始まるということです。それが私が最初に見つけることです。

位置が「固定」されていない場合は、すべて6列から始まらないと仮定すると、3行目の日付も最後の2列ではありません。混乱した例です。とにかくそれは可能です。さまざまな種類の日付文字列とそれぞれの処理方法を評価するには、より多くのロジックが必要です。繰り返しますが、これは実際には入力データ品質(GIGO)によって異なります。

これは、GNU bashとコアユーティリティを介してさまざまな方法で実行できます。強調する主なツールは、日付の有効性を評価して正規化するGNU dateコマンドです。この例では、「UTC 2023」は技術的にGNUの日付が間違っていないことを確認する有効な日付です(そしてbashでキャプチャする必要があります)。しかし、このような問題は非常に簡単で高精度で解決できます。

したがって、すべての日付文字列が列6から始まるか、有効な日付が最後の2つの列にあるとします。

while read line; do
    echo $line

    DATE_SIX="$(echo $line | cut -f6- -d' ')"
    if date --utc --date "${DATE_SIXE}" &> /dev/null; then
        DATE_SIX_NORMAL="$(date --utc --date "${DATE_SIX}")"
        DATE_SIX_EPOCH="$(date --utc --date "${DATE_SIX}" +%s)"
    else
        DATE_SIX_NORMAL="BAD DATE"
        DATE_SIX_EPOCH=0
    fi
    echo "DATE_SIX='${DATE_SIX}', DATE_SIX_NORMAL='${DATE_SIX_NORMAL}', DATE_SIX_EPOCH=${DATE_SIX_EPOCH}"

    DATE_LAST_TWO="$(echo $line | awk '{print $(NF-1)" "$(NF)}')"
    if [[ "${DATE_LAST_TWO}" != *":"* ]] || [[ "${DATE_LAST_TWO}" != *"/"* ]]; then
        # GNU date evaluates "UTC 2023" as a valid date, but it's not what's wanted ...
        DATE_LAST_TWO_NORMAL="BAD DATE"
        DATE_LAST_TWO_EPOCH=0
    else
        if date --utc --date "${DATE_LAST_TWO}" &> /dev/null; then
            DATE_LAST_TWO_NORMAL="$(date --utc --date "${DATE_LAST_TWO}")"
            DATE_LAST_TWO_EPOCH="$(date --utc --date "${DATE_LAST_TWO}" +%s)"
        else
            DATE_LAST_TWO_NORMAL="BAD DATE"
            DATE_LAST_TWO_EPOCH=0
        fi
    fi
    echo "DATE_LAST_TWO='${DATE_LAST_TWO}', DATE_LAST_TWO_NORMAL='${DATE_LAST_TWO_NORMAL}', DATE_LAST_TWO_EPOCH=${DATE_LAST_TWO_EPOCH}"

    echo
done < in.tmp

その出力は以下の通りです。もちろん、DATE_EPOCHは比較のための整数として使用できます。

A Version: x_02.28.03.03 000000 aaa 2019/05/21 03:33:04
DATE_SIX='2019/05/21 03:33:04', DATE_SIX_NORMAL='Tue May 21 03:33:04 AM UTC 2019', DATE_SIX_EPOCH=1558409584
DATE_LAST_TWO='2019/05/21 03:33:04', DATE_LAST_TWO_NORMAL='Tue May 21 03:33:04 AM UTC 2019', DATE_LAST_TWO_EPOCH=1558409584

B Version: x_02.28.03.03 000000 aaa 2019/05/21 03:33:04
DATE_SIX='2019/05/21 03:33:04', DATE_SIX_NORMAL='Tue May 21 03:33:04 AM UTC 2019', DATE_SIX_EPOCH=1558409584
DATE_LAST_TWO='2019/05/21 03:33:04', DATE_LAST_TWO_NORMAL='Tue May 21 03:33:04 AM UTC 2019', DATE_LAST_TWO_EPOCH=1558409584

C Version: 0.01.011 #3 PREEMPT Tue Apr 4 09:14:17 UTC 2023
DATE_SIX='Tue Apr 4 09:14:17 UTC 2023', DATE_SIX_NORMAL='Tue Apr  4 09:14:17 AM UTC 2023', DATE_SIX_EPOCH=1680599657
DATE_LAST_TWO='UTC 2023', DATE_LAST_TWO_NORMAL='BAD DATE', DATE_LAST_TWO_EPOCH=0

...cutに加えて、awk、bash文字列操作などの他の方法があります。

GNU dateコマンドはタイムスタンプを変換して正規化できます。

また、タイムゾーンのない元の日付はUTCであると仮定します。

ただし、カスタムタイムゾーンを指定することもできます(たとえば、日付の前にTZを使用)。

例えば、

$ date --utc --date="2019/05/21 03:33:04"
Tue May 21 03:33:04 AM UTC 2019
$ date --utc --date="Tue Apr 4 09:14:17 UTC 2023"
Tue Apr  4 09:14:17 AM UTC 2023

または、生の日付文字列をエポック時間に変換します。

$ date --utc --date="2019/05/21 03:33:04" +%s
1558409584
 date --utc --date="Tue Apr 4 09:14:17 UTC 2023" +%s
1680599657

...または man date(1) または FORMAT コントロールのオプションの組み合わせを使用します。

$ date --utc --date="2019/05/21 03:33:04" --rfc-email
Tue, 21 May 2019 03:33:04 +0000
$ date --utc --date="2019/05/21 03:33:04" +%Y%m%d%H%M%S
20190521033304
 date --utc --date="Tue Apr 4 09:14:17 UTC 2023" +%s
1680599657
$ TZ=America/New_York date --date="Tue Apr 4 09:14:17 UTC 2023"
Tue Apr  4 05:14:17 AM EDT 2023

比較のために、私はunix epochタイムスタンプを好みます。

おすすめ記事