【问题标题】:extract data from log file in specified range of time with awk getline bash使用 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 中获得的结果的图像

标签: bash parsing awk logfiles


【解决方案1】:

问题可能只是你没有引用你的 shell 变量。看:

$ foo='ab cd'

$ awk -v bar="$foo" 'BEGIN{print bar}'
ab cd

$ awk -v bar=$foo 'BEGIN{print bar}'
awk: fatal: cannot open file `BEGIN{print 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
    猜你喜欢
    • 2011-11-26
    • 1970-01-01
    • 2018-04-14
    • 2011-09-10
    • 2018-06-22
    • 2013-02-28
    • 2016-08-24
    • 2021-01-29
    • 1970-01-01
    相关资源
    最近更新 更多