付録

付録

次のデータ構造を含むCSVがあります。

1111,2222,3333,4444,5555,6666,7777,2017-1-5 1:07:09,2017-1-5 1:11:53
1111,2222,3333,4444,5555,6666,7777,2017-11-25 19:57:17,2017-11-25 19:58:54

日付、月、日を常に2桁で表示したいです。また、時間フィールドは常に2桁になりたいです。

月/日/時間フィールドが単一の数値である場合(上記の例の行のように)、本質的にゼロを前に追加します。

awkを使用すると、次の結果をどのように取得できますか?

1111,2222,3333,4444,5555,6666,7777,2017-01-05 01:07:09,2017-01-05 01:11:53
1111,2222,3333,4444,5555,6666,7777,2017-11-25 19:57:17,2017-11-25 19:58:54

答え1

優れたテキスト処理ツールは次のとおりです。アッ。次の例では、FreeBSD 11.1 で標準標準 awk を使用しています。 GNU awkを好むなら、@RomanPerekhrestは別の答えにエレガントなソリューションを提供します。

入力内容はカンマで区切られます。したがって、awkパラメータを使用して呼び出します-F,

その後、このステートメントを使用して列を印刷できますprint$1最初の列です。$22番目の列です。

$ awk -F, '{ print $8 }' inputfile.csv
2017-1-5 1:07:09
2017-11-25 19:57:17

これは各行の8番目の列を提供します。

これは作業したい日付フィールドです。区切り文字を設定するためにコマンドライン引数を使用する代わりに、これをスクリプトの一部として設定できます。 FS は入力区切り文字として使用され、OFS は出力区切り文字として使用されます。

$ awk 'BEGIN { FS = "," } ; { print $8 }' inputfile.csv
2017-1-5 1:07:09
2017-11-25 19:57:17

日付を扱うとき、私は通常、date日付が正しく処理されることを確認するためにutilを使用することを好みます。普通かGNU awkを使っているのか心配する必要はありません。また、日付を誤って解析すると、大きな失敗が発生します。

興味深いパラメータは次のとおりです。

-j     Specify we do not want to set the date at all
-f     The format string we use for input
+      The format string we use for output

したがって、この日付を実行すると、次のようになります。

$ date -j -f "%Y-%m-%d %H:%M:%S" +"%Y-%m-%d %H:%M:%S" "2017-1-5 1:07:09"
2017-01-05 01:07:09

その後、これをawkと組み合わせることができます。引用符がどのように見えるかを確認してください。脱出する。初心者にとっては、これが最大の障害になる可能性があります。

$ awk -F, '{ system("date -j -f \"%Y-%m-%d %H:%M:%S\" +\"%Y-%m-%d %H:%M:%S\" \""$8"\"")}' inputfile.csv
2017-01-05 01:07:09
2017-11-25 19:57:17

システムコールは正しいようですが、残念ながら戻りコードをキャプチャして出力に直接印刷することができます。これを防ぐためにこのパターンを使用してくださいcmd | getline。次の簡単な例では、現在の日付をmydateとして読みます。

$ awk 'BEGIN { cmd = "date"; cmd | getline mydate; close(cmd); print mydate }'
Thu Mar  1 16:26:15 CET 2018

BEGINこの簡単な例では入力がないため、キーワードを使用します。

それでは少し拡張してみましょう。

awk 'BEGIN { FS=","; OFS=FS };
     { 
         cmd = "date -j -f \"%Y-%m-%d %H:%M:%S\" +\"%Y-%m-%d %H:%M:%S\" \""$8"\"";
         cmd | getline firstdate;
         close(cmd);
         cmd = "date -j -f \"%Y-%m-%d %H:%M:%S\" +\"%Y-%m-%d %H:%M:%S\" \""$9"\"";
         cmd | getline seconddate;
         close(cmd);
         print $1,$2,$3,$4,$5,$6,$7,firstdate,seconddate
     }' inputfile.csv

1行に縮小できます。

awk 'BEGIN {FS=",";OFS=FS};{cmd="date -j -f \"%Y-%m-%d %H:%M:%S\" +\"%Y-%m-%d %H:%M:%S\" \""$8"\"";cmd | getline firstdate;close(cmd);cmd="date -j -f \"%Y-%m-%d %H:%M:%S\" +\"%Y-%m-%d %H:%M:%S\" \""$9"\"";cmd | getline seconddate;close(cmd);print $1,$2,$3,$4,$5,$6,$7,firstdate,seconddate}' inputfile.csv

結果は次のとおりです。

1111,2222,3333,4444,5555,6666,7777,2017-01-05 01:07:09,2017-01-05 01:11:53
1111,2222,3333,4444,5555,6666,7777,2017-11-25 19:57:17,2017-11-25 19:58:54

付録

ここでの目的は良い習慣を学ぶことですので、この答えを更新することをお勧めします。コードを複製するのは悪い習慣です。これを開始したら、すべてを関数に分割する必要があります。以下のコードがすぐに読みやすくなることを確認できます。

awk 'function convertdate(the_date) {
         cmd = "date -j -f \"%Y-%m-%d %H:%M:%S\" +\"%Y-%m-%d %H:%M:%S\" \""the_date"\"";
         cmd | getline formatted_date;
         close(cmd);
         return formatted_date
     }
     BEGIN { FS=","; OFS=FS };
     { 
         print $1,$2,$3,$4,$5,$6,$7,convertdate($8),convertdate($9)
     }' inputfile.csv

習慣を取ると、後でエラー処理を導入するのがどれほど簡単かがわかります。

答え2

GNU awkがある場合は、最後のフィールドをスペースで区切られたフィールドに変換できます。日付仕様文字列を入力し、必要に応じて次のようにフォーマットを再指定しますstrftime

awk 'BEGIN{OFS=FS=","} {gsub(/[-:]/," ",$NF); $NF = strftime("%Y-%m-%d %H:%M:%S", mktime($NF))} 1' file
1111,2222,3333,4444,5555,6666,7777,2017-1-5 1:07:09,2017-01-05 01:11:53
1111,2222,3333,4444,5555,6666,7777,2017-11-25 19:57:17,2017-11-25 19:58:54

バラよりGNU awkユーザーガイド:時間関数

答え3

シンプルなGNUawk解決策:

awk 'BEGIN{ FS=OFS="," }{ gsub(/\<[0-9]\>/, "0&", $8); gsub(/\<[0-9]\>/, "0&", $9) }1' file
  • gsub(/\<[0-9]\>/, "0&", <field>)- 個々の1桁の数字のみを置き換え/補足日時ひも:
    • \<\>- 単語の境界。
    • &- 正規表現パターン一致の正確な部分文字列を表します。

出力:

1111,2222,3333,4444,5555,6666,7777,2017-01-05 01:07:09,2017-01-05 01:11:53
1111,2222,3333,4444,5555,6666,7777,2017-11-25 19:57:17,2017-11-25 19:58:54

答え4

これ日付ツールパッケージには、時間/日付形式データの詳細を処理するコードがあります。

# Utility functions: print-as-echo, print-line-with-visual-space.
pe() { for _i;do printf "%s" "$_i";done; printf "\n"; }
pl() { pe;pe "-----" ;pe "$*"; }

pl " Input data file $FILE:"
head $FILE

pl " Expected output:"
cat $E

pl " Results, to standard format:"
dateutils.dconv -S <$FILE

pl " Results, to standard format, omitting the \"T\":"
dateutils.dconv -S -f '%F %T' <$FILE

生産:

-----
 Input data file data1:
1111,2222,3333,4444,5555,6666,7777,2017-1-5 1:07:09,2017-1-5 1:11:53
1111,2222,3333,4444,5555,6666,7777,2017-11-25 19:57:17,2017-11-25 19:58:54

-----
 Expected output:
1111,2222,3333,4444,5555,6666,7777,2017-01-05 01:07:09,2017-01-05 01:11:53
1111,2222,3333,4444,5555,6666,7777,2017-11-25 19:57:17,2017-11-25 19:58:54

-----
 Results, to standard format:
1111,2222,3333,4444,5555,6666,7777,2017-01-05T01:07:09,2017-01-05T01:11:53
1111,2222,3333,4444,5555,6666,7777,2017-11-25T19:57:17,2017-11-25T19:58:54

-----
 Results, to standard format, omitting the "T":
1111,2222,3333,4444,5555,6666,7777,2017-01-05 01:07:09,2017-01-05 01:11:53
1111,2222,3333,4444,5555,6666,7777,2017-11-25 19:57:17,2017-11-25 19:58:54

そのようなシステムでは:

OS, ker|rel, machine: Linux, 3.16.0-4-amd64, x86_64
Distribution        : Debian 8.9 (jessie) 
bash GNU bash 4.3.30
dateutils.dconv dconv 0.3.1

dconvの詳細:

dateutils.dconv Convert DATE/TIMEs between calendrical systems. (man)
Path    : /usr/bin/dateutils.dconv
Package : dateutils
Home    : http://www.fresse.org/dateutils
Version : 0.3.1
Type    : ELF 64-bit LSB shared object, x86-64, version 1 ( ...)
Help    : probably available with -h,--help
Home    : https://github.com/hroptatyr/dateutils (doc)

頑張って...乾杯、drl

関連情報