付録

付録

次のデータ構造を含む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

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

おすすめ記事