我有一个Nginx日志文件,我想根据Ips分成多个文件。例如,我有ips1.txt
和ips2.txt
。每个文件具有日志文件唯一ip数量的一半。 Nginx日志文件具有以下格式:
172.0.0.10 - [24/Jun/2018:11:00:00 +0000] url1 GET url2 HTTP/1.1 (200) 0.000 s 2356204 b url3 - - [HIT] - s - Mozilla/5.0 (X11; CrOS x86_64 10452.99.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.203 Safari/537.36
172.0.0.11 - [24/Jun/2018:11:00:00 +0000] url1 GET url2 HTTP/1.1 (200) 0.000 s 307 b url3 - - [HIT] - s - Mozilla/5.0 (X11; CrOS x86_64 10452.99.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.203 Safari/537.36
因此,我要获取所有以模式文件中的IP开头的行的操作是
cat log.txt | grep -f ips1.txt > part1.txt
cat log.txt | grep -f ips2.txt > part2.txt
我知道我正在做的grep在整个行中搜索,而不仅仅是在开始时。这使搜索速度变慢,浪费了更多的内存。我知道是否只有一种模式可以使用awk
(例如awk '{if($1 == "172.0.0.10")print;}' log.txt
),但是我不知道如何使用grep使用模式文件来实现。
因此,我想要的是减少浪费的存储空间,并通过仅在行的开头进行查找来加快搜索速度。我的日志文件有很多GB,如果可以的话,我会节省很多时间。
编辑:
我的ips * .txt文件是根据我拥有的线程数生成的。您可以在下面看到我的代码如何:
NUM_THREADS=8
export LC_ALL=C
unpigz -c log.gz | awk '{print $1;}' | LC_ALL=C sort -S 20% -u > all_ips.txt
lines_arq=$(wc -l all_ips.txt | cut -d' ' -f1)
lines_each_file=$(($lines_arq / $NUM_THREADS + 50))
split --lines=$lines_each_file all_ips.txt 2018/prefixo.
zgrep log.gz -Fwf 2018/prefixo.aa | pigz > file1.gz &
zgrep log.gz -Fwf 2018/prefixo.ab | pigz > file2.gz &
...
zgrep log.gz -Fwf 2018/prefixo.ah | pigz > file8.gz &
wait
unpigz -c file1.gz | pypy script.py -i - -o onOff -s 11:00:00 -m testing -y 2018 | pigz > onOff-file1.gz &
...
unpigz -c file8.gz | pypy script.py -i - -o onOff -s 11:00:00 -m testing -y 2018 | pigz > onOff-file8.gz &
答案 0 :(得分:2)
整个过程都使用awk。首先阅读固定的字符串,然后拆分日志。例如:
awk '{out[$1] = FILENAME ".out"}
END {while (getline < input) { print > out[$1] }}
' input=log.txt ips[12].txt
多次读取输入文件将大大损害您的性能,而不是不必要地awk拆分行的开销。
下面是代码的简要说明。第一个(也是唯一的)命令是读取输入并构建文件名数组。列出所有ips * .txt作为输入,因此将这些行读入数组。理想情况下,这些文件相对较小,因此构建此阵列不会花费很多精力。构建阵列后,您输入END子句,在其中读取日志文件(仅一次!),并将每一行写入相应的文件。
似乎您想动态生成ips * .txt,并且只想分发日志。在这种情况下,请尝试以下操作:
awk '! ($1 in out) {out[$1] = (idx++ %10) }
{ outfile= "output." out[$1] ".txt"; print > outfile ; next} ' log.txt
这只是检查您是否已经看过ip:如果已经看过ip,然后将其写到与上一个日志相同的文件中。如果没有,增加一个计数器(模数10 ...根据所需的文件数量选择模数)并写入该文件,记录您要在哪行写入行。对日志中的每一行重复。
这里的关键是最大程度地减少您阅读日志的次数。
答案 1 :(得分:2)
这里有一些加快指令速度的想法。确保对它们进行基准测试。我丢失了数据以自己对它们进行基准测试。
zgrep file
上使用unpigz -c file | grep
LC_ALL=C zgrep ...
-F
和单词正则表达式-w
。固定字符串搜索应该比默认的基本正则表达式搜索快一点。对于固定的字符串大小写,单词正则表达式是最接近您»搜索的内容,仅在行的开头。grep -Fwf ip...
。或
^
添加到开头以仅在行的开头进行搜索。然后使用grep -E
或grep -P "$regex"
/ pcregrep "$regex"
。 -E
和-P
的速度可以相差很多。选中两者,看看哪一个更快。regex="$(tr \\n \| < ips1.txt | sed 's/^/^(/;s/\./\\./g;s/$/)/')"
zgrep -E "$regex" yourfile > part1.txt
zgrep -Ev "$regex" yourfile > part2.txt