通过使用命令行工具日期分割access.log文件(Split access.log file by

2019-06-26 13:52发布

我有一个Apache的access.log文件,这是35GB左右的规模。 通过它Grepping是不是一种选择更多,而无需等待一个很大的。

我想用日期为分裂标准来它在许多小文件分割。

日期是在格式[15/Oct/2011:12:02:02 +0000] 任何想法我怎么能只使用bash的脚本,标准的文本处理程序(的grep,awk中,sed和喜欢),管道和重定向它做什么?

输入文件名是access.log 。 我想输出文件有格式,如access.apache.15_Oct_2011.log (会做的伎俩,虽然不是很好排序时。)

Answer 1:

使用一种方法awk

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 E3127070秒,虽然这种方法用了5秒。

最初的设计灵感:“ 如何通过拆分一个月现有的Apache日志文件? ”



Answer 2:

纯bash中,使得一次通过访问日志:

while read; do
    [[ $REPLY =~ \[(..)/(...)/(....): ]]

    d=${BASH_REMATCH[1]}
    m=${BASH_REMATCH[2]}
    y=${BASH_REMATCH[3]}

    #printf -v fname "access.apache.%s_%s_%s.log" ${BASH_REMATCH[@]:1:3}
    printf -v fname "access.apache.%s_%s_%s.log" $y $m $d

    echo "$REPLY" >> $fname
done < access.log


Answer 3:

Perl的赶来救援:

cat access.log | perl -n -e'm@\[(\d{1,2})/(\w{3})/(\d{4}):@; open(LOG, ">>access.apache.$3_$2_$1.log"); print LOG $_;'

嗯,这不是很“标准”处理程序,但它是文本处理还是取得。

我也是在文件名更改的参数顺序,以文件被命名为喜欢access.apache.yyyy_mon_dd.log方便分页。



Answer 4:

下面是一个awk输出词法排序的日志文件版本。

一些效率增强功能:在同一个一遍完成,只产生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 5:

我结合西奥多的和索尔的解决方案使用托尔的效率提高和日常文件,但保留在组合格式文件的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 6:

的丑样,那是你的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


Answer 7:

我做了一个轻微的改善西奥多的答案,所以我可以看到进步处理一个非常大的日志文件时。

#!/usr/bin/awk -f

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]])

    current = year "-" month
    if (last != current)
        print current
    last = current

    print >> FILENAME "-" year "-" month ".txt"
}

此外,我发现,我需要使用gawkbrew install gawk ,如果你没有的话),对于这个在Mac OS X上运行



文章来源: Split access.log file by dates using command line tools