web-dev-qa-db-ja.com

awkでタイムスタンプを変換するときに無効な日付

ログファイルのタイムスタンプをUnixタイムスタンプに変換する方法を探しています。これまでに思いついたコマンドは次のとおりです。

awk -F'[' '{ print $2}' | awk -F']' '{cmd ="date \"+%s\" -d \""$1"\""; cmd | getline var; print var $2; close(cmd)}'

コマンドは、元のタイムスタンプにUTCがタイムゾーンとして含まれている場合、またはタイムゾーンが指定されていない場合に機能します。ただし、タイムゾーンが別の場合は失敗します。たとえば、これは動作します:

$ entry="[08-May-2020 15:40:32 UTC] PHP Warning:  Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 1290"
$ echo "$entry" | awk -F'[' '{ print $2}' | awk -F']' '{cmd="date \"+%s\" -d \""$1"\""; cmd | getline var; print var $2; close(cmd)}'
1588952432 PHP Warning:  Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 1290

また、コマンドはタイムゾーンが指定されていない場合にも機能します。

$ entry="[08-May-2020 15:40:32] PHP Warning:  Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 1290"
$ echo "$entry" | awk -F'[' '{ print $2}' | awk -F']' '{cmd="date \"+%s\" -d \""$1"\""; cmd | getline var; print var $2; close(cmd)}'
1588948832 PHP Warning:  Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 1290

ただし、タイムゾーンがEurope/London失敗しました:

$ entry="[08-May-2020 15:40:32 Europe/London] PHP Warning:  Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 1290"
$ echo "$entry" | awk -F'[' '{ print $2}' | awk -F']' '{cmd="date \"+%s\" -d \""$1"\""; cmd | getline var; print var $2; close(cmd)}'
date: invalid date ‘08-May-2020 15:40:32 Europe/London’
 PHP Warning:  Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 1290

Awkコマンドのデバッグ方法は本当にわかりません。タイムゾーンのスラッシュが気に入らないのではないかと思いますが、それは推測にすぎません。

3
rkhff

日付がTZ変数を受け取る(そしてそれを理解する)方法は、かなり注意が必要です。このコマンドは機能します:

_ $ date -d 'TZ="UTC" 08-May-2020 15:40:32' +"%s"
1588952432
_

同様に、OlsonデータベースのTZ:

_$ date -d 'TZ="Europe/London" 08-May-2020 15:40:32' +"%s" 
1588948832
_

また、エポック時間は_1588952432_と_1588948832_で異なることに注意してください。ロンドンが_-1_であり、UTCが_0_であるため、1時間の差。

形式が非常に厳密であることを理解してください。TZが最初に、すべてが単一引用符で囲まれ、TZ値も二重引用符で囲まれます。そして、とても厳格であり、また非常にもろい。

したがって、配列に値を設定します(bash、ksh、またはzshを想定)。

_entry=( 
        "[08-May-2020 15:40:32 UTC] PHP Warning:  Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 1290"
        "[08-May-2020 15:40:32] PHP Warning:  Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 1290"
        "[08-May-2020 15:40:32 Europe/London] PHP Warning:  Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 1290"
      )
_

次に、awkを使用して日付からすべての値を取得できます(awkへの1回の呼び出しで異なるFSに注意してください(技術的に言えば、GNU awkまたはnawk)および時間文字列の要素の数が異なるため分割を使用する):

_printf '%s\n' "${entry[@]}" | awk -F '[][]' '{
    n=split($2, val, / /, sep);
    cmd=sprintf("date +\"%%s\" -d '\''TZ=\"%s\" %s %s'\''",val[3],val[1],val[2]);
    cmd | getline var; close(cmd);
    print "["var"]"$3;
}'
[1588952432] PHP Warning:  Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 1290
[1588952432] PHP Warning:  Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 1290
[1588948832] PHP Warning:  Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 1290
_

技術的には次のような行に注意してください:

_if ( (rc=(cmd | getline var)) != 1){ 
     print "error on calling the command date ",rc; exit 
};
_

Getlineのいくつかのエラーをキャッチしますが(基本的にgetlineはコマンドから出力を取得できません)、awkはコマンドからのエラー番号を報告したり処理したりできません。それが必要な場合、実行を中断するのはコマンドの責任です。 awkが行う唯一のこと(エラーかどうか)は、cmdのstderr出力を直接そのstderrに渡すことです。したがって、awkのstderrでコマンドによって発生したコメント(またはエラー)が表示されます。必要に応じて、これらを確認して処理してください。そうでない場合、出力ファイルは静かに破損します。警告されました!。それはあなたが求めているもののようです。

いいえ、awk datetime()は、TZ時間、さらにはOlsonデータベースからの値を理解できません。

3
Isaac

@Isaacは正しい軌道にあり、入力に対してはおそらくうまくいくので、彼を受け入れられた回答として残してください。ただし、入力が予期される[date+time]文字列で開始されない場合をキャッチするには、このようにします、dateの呼び出しが失敗するか、getlineが失敗するため、タイムスタンプの後に来るメッセージテキストに]がある場合は成功し、一部の場合は失敗終了ステータスで終了します。実行の失敗:

$ cat tst.awk
match($0,/\[[^]]+] /) {
    dt  = substr($0,RSTART+1,20)
    tz  = substr($0,RSTART+22,RLENGTH-24)
    msg = substr($0,RSTART+RLENGTH)

    cmd = sprintf("date -d \047TZ=\"%s\" %s\047 +\047%%s\047", tz, dt)
    cmd | getline secs
    close(cmd)
}
secs == "" {
    printf "%s[%d]: failed to convert: \"%s\"\n", FILENAME, NR, $0 | "cat>&2"
    exit 1
}
{ print secs, msg; secs="" }

例えばこの入力ファイルが与えられた場合(最後の2行に注意してください-最初の行はメッセージ部分に]があり、2番目の行は無効な日付です):

$ cat file
[08-May-2020 15:40:32 UTC] PHP Warning:  Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 1290"
[08-May-2020 15:40:32] PHP Warning:  Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 1290
[08-May-2020 15:40:32 Europe/London] PHP Warning:  Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 290
[08-May-2020 15:40:32 Europe/London] PHP Warning:  array foo[] is bad, the sky is falling
[08-Bob-2020 15:40:32 Europe/London] PHP Warning:  Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 290

$ awk -f tst.awk file
1588952432 PHP Warning:  Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 1290"
1588952432 PHP Warning:  Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 1290
1588948832 PHP Warning:  Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 290
1588948832 PHP Warning:  array foo[] is bad, the sky is falling
date: invalid date ‘TZ="Europe/London" 08-Bob-2020 15:40:32’
file[5]: failed to convert: "[08-Bob-2020 15:40:32 Europe/London] PHP Warning:  Illegal string offset 'ID' in /home/example/public_html/wp-content/themes/example/functions.php on line 290"

$ echo "$?"
1

失敗ステータスで終了する最後の部分は重要なので、失敗した場合でもawk出力が入力ファイルを上書きすることを心配せずにawk 'script' file > tmp && mv tmp fileのようなスクリプトを記述できます。そうでない場合は、awk 'script' fileの結果をテストできます。

2
Ed Morton