bash - 分割 - tee コマンド
コマンドラインツールを使用してaccess.logファイルを日付別に分割 (5)
私は約35GBのサイズのApache access.logファイルを持っています。 グレープスルーはそれ以上のオプションではなく、大したことを待たずに。
分割基準として日付を使用して、多くの小さなファイルに分割したいと思っていました。
日付は[15/Oct/2011:12:02:02 +0000]
形式です。 どのようにしてbashスクリプト、標準的なテキスト操作プログラム(grep、awk、sedなど)、配管とリダイレクトのみを使用すればよいでしょうか?
入力ファイル名はaccess.log
です。 私は出力ファイルにaccess.apache.15_Oct_2011.log
ようなフォーマットを持たせたいと思っています。
https://src-bin.com
Answer #1
Perlは救助に来た:
cat access.log | perl -n -e'[email protected]\[(\d{1,2})/(\w{3})/(\d{4}):@; open(LOG, ">>access.apache.$3_$2_$1.log"); print LOG $_;'
まあ、正確には "標準"の操作プログラムではありませんが、テキスト操作のために作られています。
また、ファイル名の引数の順序を変更しました。ファイルの名前はaccess.apache.yyyy_mon_dd.logのように簡単に並べ替えられます。
Answer #2
awk
を使用する1つの方法:
awk 'BEGIN {
split("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ", months, " ")
for (a = 1; a <= 12; a++)
m[months[a]] = a
}
{
split($4,array,"[:/]");
year = array[3]
month = sprintf("%02d", m[array[2]])
print > FILENAME"-"year"_"month".txt"
}' incendiary.ws-2009
これは次のようなファイルを出力します:
incendiary.ws-2010-2010_04.txt
incendiary.ws-2010-2010_05.txt
incendiary.ws-2010-2010_06.txt
incendiary.ws-2010-2010_07.txt
150 MBのログファイルに対して、chepnerの回答は3.4 GHzの8コアXeon E31270で70秒、この方法では5秒かかりました。
オリジナルのインスピレーション:「 既存のApacheログファイルを月ごとに分割する方法は? 」
Answer #3
字句解析可能なログファイルを出力するawk
版があります。
いくつかの効率改善:すべてが1つのパスで実行され、以前と同じでないときはfname
生成し、新しいファイルに切り替えるときはfname
閉じます(そうでなければファイル記述子が足りなくなる可能性があります)。
awk -F"[]/:[]" '
BEGIN {
m2n["Jan"] = 1; m2n["Feb"] = 2; m2n["Mar"] = 3; m2n["Apr"] = 4;
m2n["May"] = 5; m2n["Jun"] = 6; m2n["Jul"] = 7; m2n["Aug"] = 8;
m2n["Sep"] = 9; m2n["Oct"] = 10; m2n["Nov"] = 11; m2n["Dec"] = 12;
}
{
if($4 != pyear || $3 != pmonth || $2 != pday) {
pyear = $4
pmonth = $3
pday = $2
if(fname != "")
close(fname)
fname = sprintf("access_%04d_%02d_%02d.log", $4, m2n[$3], $2)
}
print > fname
}' access-log
Answer #4
私はTheodoreとThorのソリューションを組み合わせて、Thorの効率改善と日々のファイルを使用しましたが、IPv6アドレスの元のサポートは結合形式ファイルで保持していました。
awk '
BEGIN {
m2n["Jan"] = 1; m2n["Feb"] = 2; m2n["Mar"] = 3; m2n["Apr"] = 4;
m2n["May"] = 5; m2n["Jun"] = 6; m2n["Jul"] = 7; m2n["Aug"] = 8;
m2n["Sep"] = 9; m2n["Oct"] = 10; m2n["Nov"] = 11; m2n["Dec"] = 12;
}
{
split($4, a, "[]/:[]")
if(a[4] != pyear || a[3] != pmonth || a[2] != pday) {
pyear = a[4]
pmonth = a[3]
pday = a[2]
if(fname != "")
close(fname)
fname = sprintf("access_%04d-%02d-%02d.log", a[4], m2n[a[3]], a[2])
}
print >> fname
}'
Answer #5
醜いもの、それはあなたのためのbashです:
for year in 2010 2011 2012; do
for month in jan feb mar apr may jun jul aug sep oct nov dec; do
for day in 1 2 3 4 5 6 7 8 9 10 ... 31 ; do
cat access.log | grep -i $day/$month/$year > $day-$month-$year.log
done
done
done