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




logfiles