我有一个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"
}
此外,我发现,我需要使用gawk
( brew install gawk
,如果你没有的话),对于这个在Mac OS X上运行
文章来源: Split access.log file by dates using command line tools