使用 awk getline bash 在指定的时间范围内从日志文件中提取数据
Posted
技术标签:
【中文标题】使用 awk getline bash 在指定的时间范围内从日志文件中提取数据【英文标题】:extract data from log file in specified range of time with awk getline bash 【发布时间】:2013-09-10 22:14:06 【问题描述】:我正在搜索解析日志文件并在此链接中找到我需要的内容 extract data from log file in specified range of time
但最有用的答案(@Kent 发布):
# this variable you could customize, important is convert to seconds.
# e.g 5days=$((5*24*3600))
x=$((5*60)) #here we take 5 mins as example
# this line get the timestamp in seconds of last line of your logfile
last=$(tail -n1 logFile|awk -F'[][]' ' gsub(/\//," ",$2); sub(/:/," ",$2); "date +%s -d \""$2"\""|getline d; print d;' )
#this awk will give you lines you needs:
awk -F'[][]' -v last=$last -v x=$x ' gsub(/\//," ",$2); sub(/:/," ",$2); "date +%s -d \""$2"\""|getline d; if (last-d<=x)print $0 ' logFile
我认为错误在"date +%s -d ....
部分
出现以下错误:
sh: -c: line 0: unexpected EOF while looking for matching `"'
sh: -c: line 1: syntax error: unexpected end of file
sh: -c: line 0: unexpected EOF while looking for matching `"'
sh: -c: line 1: syntax error: unexpected end of file
在我在这里提问之前我花了很多时间试图解决,但没有找到任何解决方案。
crontab
将调用该脚本以获取最后 1 分钟的日志行,并计算一个 ip 在一分钟内列出了多少次,这样我就可以检测它是否是攻击。这是另一项任务,希望专家能帮助在同一问题中提供所需的代码。(我认为它可以用 2 行解决)。
【问题讨论】:
为什么要重新发明***?已经有一些工具可以做这样的事情。 这些错误消息似乎表明您在某处的字符串上遗漏了右双引号。我猜它可能在第 132 行,第 37 位,就在第三个if
语句之前,但这完全是猜测,因为您还没有发布实际代码....
代码发布在链接中,我提到最有用的答案就是那个问题。无论如何我都会编辑这个问题。这是阐明 .sh 文件、日志文件和在终端 postimg.org/image/lih0v0gzx 中获得的结果的图像
【参考方案1】:
问题可能只是你没有引用你的 shell 变量。看:
$ foo='ab cd'
$ awk -v bar="$foo" 'BEGINprint bar'
ab cd
$ awk -v bar=$foo 'BEGINprint bar'
awk: fatal: cannot open file `BEGINprint bar' for reading (No such file or directory)
是的,我知道这是一条不同的错误消息——当你不引用 shell 变量时会发生什么,这取决于变量的值、目录的内容等,其中一些非常糟糕,比如删除文件系统中的每个文件。
所以,引用你的变量:
-v last="$last" -v x="$x"
然后看看你是否还有问题。
顺便说一下,这里是如何使用 GNU awk 和输入文件 http://pastebin.com/BXmS4zLn 真正解决您的原始问题:
$ cat tst.awk
BEGIN
ARGV[ARGC++] = ARGV[ARGC-1]
mths = "JanFebMarAprMayJunJulAugSepOctNovDec"
if (days) hours = days * 24
if (hours) mins = hours * 60
if (mins) secs = mins * 60
deltaSecs = secs
NR==FNR
nr2secs[NR] = mktime($6" "(match(mths,$5)+2)/3" "$4" "gensub(/:/," ","g",$7))
next
nr2secs[FNR] >= (nr2secs[NR-FNR] - deltaSecs)
$ awk -v hours=1 -f tst.awk file
157.55.34.99 - - 06 Sep 2013 09:13:10 +0300 "GET /index.php HTTP/1.1" 200 16977 "-" "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)"
85.163.134.149 - - 06 Sep 2013 09:50:23 +0300 "GET /wap/wapicons/mnrwap.jpg HTTP/1.1" 200 1217 "http://mydomain.com/main.php" "Mozilla/5.0 (Linux; U; android 4.1.2; en-gb; GT-I9082 Build/JZO54K) AppleWebKit/534.30 (Khtml, like Gecko) Version/4.0 Mobile Safari/534.30"
83.113.48.218 - - 06 Sep 2013 10:13:07 +0300 "GET /english/nicons/word.gif HTTP/1.1" 200 803 "http://mydomain.com/french/details.php?eid=127928&cid=18&fromval=1&frid=18" "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0; Trident/5.0)"
$ gawk -v mins=60 -f tst.awk file
157.55.34.99 - - 06 Sep 2013 09:13:10 +0300 "GET /index.php HTTP/1.1" 200 16977 "-" "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)"
85.163.134.149 - - 06 Sep 2013 09:50:23 +0300 "GET /wap/wapicons/mnrwap.jpg HTTP/1.1" 200 1217 "http://mydomain.com/main.php" "Mozilla/5.0 (Linux; U; Android 4.1.2; en-gb; GT-I9082 Build/JZO54K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30"
83.113.48.218 - - 06 Sep 2013 10:13:07 +0300 "GET /english/nicons/word.gif HTTP/1.1" 200 803 "http://mydomain.com/french/details.php?eid=127928&cid=18&fromval=1&frid=18" "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0; Trident/5.0)"
$ gawk -v mins=20 -f tst.awk file
83.113.48.218 - - 06 Sep 2013 10:13:07 +0300 "GET /english/nicons/word.gif HTTP/1.1" 200 803 "http://mydomain.com/french/details.php?eid=127928&cid=18&fromval=1&frid=18" "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0; Trident/5.0)"
您可以指定 days= 或 hours= 或 mins= 或 secs= 变量,它会做正确的事情。
如果您只需要一个脚本来获取您的问题所述的最后 1 分钟的日志行(现在?),并且希望看到一个单行来做到这一点:
$ gawk 'NR==FNR nr2secs[++nr] = mktime($6" "(match("JanFebMarAprMayJunJulAugSepOctNovDec",$5)+2)/3" "$4" "gensub(/:/," ","g",$7)); next nr2secs[FNR] >= (nr2secs[nr] - 60)' file file
83.113.48.218 - - 06 Sep 2013 10:13:07 +0300 "GET /english/nicons/word.gif HTTP/1.1" 200 803 "http://mydomain.com/french/details.php?eid=127928&cid=18&fromval=1&frid=18" "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0; Trident/5.0)"
【讨论】:
【参考方案2】:根据您的输入 here,您可以使用如下脚本:
#!/bin/bash
LOGFILE=/path/to/logfile
X=$(( 60 * 60 )) ## 1 Hour
function get_ts
DATE="$1%%\]*"; DATE="$DATE##*\["; DATE=$DATE/:/ ; DATE=$DATE//\//
TS=$(date -d "$DATE" '+%s')
get_ts "$(tail -n 1 "$LOGFILE")"
LAST=$TS
while read -r LINE; do
get_ts "$LINE"
(( (LAST - TS) <= X )) && echo "$LINE"
done < "$LOGFILE"
将其保存到文件并更改 LOGFILE 的值,然后使用 bash script.sh
运行。
示例输出:
157.55.34.99 - - [06/Sep/2013:09:13:10 +0300] "GET /index.php HTTP/1.1" 200 16977 "-" "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)"
85.163.134.149 - - [06/Sep/2013:09:50:23 +0300] "GET /wap/wapicons/mnrwap.jpg HTTP/1.1" 200 1217 "http://mydomain.com/main.php" "Mozilla/5.0 (Linux; U; Android 4.1.2; en-gb; GT-I9082 Build/JZO54K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30"
【讨论】:
显示相同的结果。我知道 crontab 功能。我的意思是该命令将计算每个 IP 并给出调用 url 的数量,然后是 IP。如果我搜索它不是主要问题,我可能会发现该命令。 @kingk110 介意向我们展示您使用的代码的一些关键部分吗?尤其是通过sh -c
调用的那个。
代码发布在链接中,我提到最有用的答案就是那个问题。无论如何我都会编辑这个问题。
@king110 这实际上是 awk 的局限性。当您从中调用外部命令时,它取决于外壳程序,并将其传递给重新评估。如果您的输入以某种方式包含可能会改变语法的字符,则会导致语法错误。确保将由 shell 评估的预期命令字符串在语法上是正确的,无论输入是否为您提供像 "
这样的危险字符。我也知道这是您的基础,但我希望这不完全是您正在运行的代码,或者至少输入不一样。请出示给我们。
这里是 .sh 文件和 logFile 以及执行结果postimg.org/image/lih0v0gzx以上是关于使用 awk getline bash 在指定的时间范围内从日志文件中提取数据的主要内容,如果未能解决你的问题,请参考以下文章