次のログ形式のログファイルがあります。
###<Aug 8, 2016 11:59:05 PM>
different text
...
different text
###<Aug 15, 2016 9:10:55 AM>
different text
...
...
...
different text
###<Aug 22, 2016 10:02:17 PM>
different text
...
...
...
...
different text
###<Sep 1, 2016 1:00:01 AM>
different text
###<Sep 7, 2016 3:00:01 PM>
different text
...
...
different text
このログファイルを日付ごとにYYYY_MM_DD.logファイルに分割するにはどうすればよいですか?
Perl
ソリューション。GNU date
を利用して日付を変換します。
Perl -ne 'if(/^###<(.*)>/){
chomp($d=`date -d \"$1\" +%Y_%m_%d`);
$name="$d.log"
}
open(my $fh,">>","$name");
print $fh $_;' file.log
-ne
:入力ファイルを1行ずつ読み取り(各行を特殊変数$_
として保存)、-e
で指定されたスクリプトを各行に適用します。if(/^###<(.*)>/)
:行が###<
で始まる場合、<>
の間のすべてを$1
としてキャプチャします(かっこがすることです)。chomp($d=
date -d\"$ 1 \" +%Y_%m_%d);
:date
コマンドは日付を再フォーマットします。例えば:
$ date -d "Sep 1, 2016 1:00:01 AM" +%Y_%m_%d
2016_09_01
chomp
は、date
の結果から最後の改行を削除するため、後で使用できます。
$name="$d.log"
:date
コマンドの結果と.log
を変数$name
として保存します。open(my $fh,">>","$name");
:ファイルハンドル$name
としてファイル$fh
を開きます。ファイルハンドルが何であるかわからなくても心配する必要はありません。これは、print $fh "foo"
がfoo
を$name
に出力することを意味します。print $fh $_;
:ファイルハンドル$fh
が指すファイルに現在の行を出力します。したがって、$name
として現在保存されているものに行を印刷します。これを解決する1つの方法は、awkを使用することです。たとえば、次のコマンド:
awk -F'[ <,]+' '/^###/{close(f);f=$4"_"$2"_"$3".log"}{print >> f}END{close(f)}' file
日付フィールドをファイル名として使用して、ファイルをファイルに分割する必要があります
awk
の場合:
awk '/^#+<[^>]+>$/ {if (lines) print lines >file; \
dt=gensub("^#+<([^>]+)>$", "\\1", $0)
dt_cmd="date -d \""dt"\" +%Y_%m_%d.log" \
dt_cmd | getline file; lines=$0; next}; \
{lines=lines ORS $0} END {print lines >file}' file.log
読み取り可能なフォーム:
awk '
/^#+<[^>]+>$/ {
if (lines)
print lines >file
dt=gensub("^#+<([^>]+)>$", "\\1", $0)
dt_cmd="date -d \""dt"\" +%Y_%m_%d.log"
dt_cmd | getline file; lines=$0
next
}
{
lines=lines ORS $0
}
END {
print lines >file
}' file.log
/^#+<[^>]+>$/
は日付を含む行と一致します。{}
で囲まれたチャンクは、条件が一致した場合にのみ実行されます。一致する場合、外部date
コマンドを使用して出力を変数file
に保存し、変数lines
の内容をファイルfile
(前のチャンクから)、変数lines
を次の行で再度インスタンス化します
他のすべての行については、行を変数lines
として連結します
最後のチャンクは、END
ブロックに入れることで保存されます