【问题标题】:Linux Shell Script: How to compare a specific field in a text document with specific text in an if statementLinux Shell 脚本:如何将文本文档中的特定字段与 if 语句中的特定文本进行比较
【发布时间】:2018-03-08 05:56:52
【问题描述】:

我有一个名为 transfer.log 的文件,其中包含一些 Apache 日志。我需要计算每个 IP 地址记录了多少 GET 请求。我知道如何访问文件并循环遍历文件中的行,但我无法将每行中的第 6 个字段与“GET”进行比较。

#!/bin/bash    

while read p; 
do
    name=( $(awk '{print $6}' p))
    echo $name
    if [ "$name" == "GET" ]
    then
            echo "yes"
    else
        echo "no"
    fi
done < transfer.log

目前,当我运行脚本“no”打印 5 次时,我收到一条错误消息,提示 awk 无法打开文件“p”。当我在变量声明中将 p 更改为 transfer.log 时,我可以让 echo $name 输出“GET(带引号),但它显然永远不会改变,因为它正在访问整个文件而不是新行 p。

我需要知道每次执行 while 循环时如何将 p 的第 6 列分配给我的变量名。另外,我对为什么我的循环只迭代 5 次而不是 6 次感到困惑。

我的 transfer.log 如下所示:

140.211.167.27 - - [15/Oct/2012:23:11:38 +0000] "GET / HTTP/1.1" 200 2963 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4"
140.211.167.27 - - [15/Oct/2012:23:11:46 +0000] "GET /systems/ganeti/index HTTP/1.1" 200 5918 "https://wiki.osuosl.org/systems/index" "Mozilla/5.0(X11; Linux x86_64) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4"
140.211.167.9 - - [15/Oct/2012:23:17:33 +0000] "GET /resources/index HTTP/1.1" 200 3411 "https://wiki.osuosl.org/index" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:15.0) Gecko/20100101 Firefox/15.0.1"
140.211.167.25 - - [15/Oct/2012:16:02:07 +0000] "GET /index HTTP/1.1" 200 2673 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:15.0) Gecko/20100101 Firefox/15.0.1"
66.249.74.101 - - [15/Oct/2012:02:20:14 +0000] "GET /robots.txt HTTP/1.1" 404 2458 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
128.193.164.34 - - [15/Oct/2012:12:41:18 +0000] "POST /rpc/xmlrpc HTTP/1.0" 200 8328 "-" "PHP XMLRPC 1.0"

最终,我需要计算每个特定 IP 地址记录了多少 GET 请求,并按从最小到最大 GET 请求对地址进行排序。

【问题讨论】:

  • awk 提取的第 6 个字段将包含值 "GET 而不是 GET!!!这就是为什么你在字符串评估中遇到问题,实际上你不需要为这个纯 awk 创建一个完整的 shell 脚本就可以了

标签: linux bash shell awk string-comparison


【解决方案1】:

您可以使用以下awk 命令来解决问题:

$ awk '{if($6=="\"GET")ip[$1]++; else ip[$1]+=0}END{for(elem in ip){print elem, ip[elem]}}' input.log | sort -k2nr
140.211.167.27 2
140.211.167.25 1
140.211.167.9 1
66.249.74.101 1
128.193.164.34 0

说明:

  • {if($6=="\"GET")ip[$1]++; else ip[$1]+=0} 在文件的每一行上,它将检查第 6 个字段,如果它等于 "GET,它将增加一个以 ip 为索引的数组;如果第 6 个字段不等于 "GET,它会将 0 添加到数组中,以便考虑已经完成某些操作的 ip POST,如果您不识别它,则可以删除此逻辑。
  • 然后在文件末尾打印每个ip加上GET的数量
  • 所有内容都通过管道传送到sort 命令,该命令将使用第二个字段对输出进行排序,并以相反的数字顺序排列

【讨论】:

    【解决方案2】:

    下面这行是错误的:

    name=( $(awk '{print $6}' p))
    

    您应该将其替换为:

    name=$(echo "$p" | awk '{print $6}')
    

    您将变量名p 传递给了应有文件名的awk。此外,外括号是多余的。

    【讨论】:

      【解决方案3】:

      我尝试解析日志文件,供大家参考:

      #!/bin/bash
      howmanyGET=0
      loopcounter=0
      while read line;do
          #echo "Line # $loopcounter: $line"
          ((loopcounter++))
          name=`echo $line | awk '{print $6}'`
          #name=( $(awk '{print $6}' p))
          #echo $name
          name=${name:1:3}
          echo $name
          if [ "$name" == "GET" ]
          then
              echo "yes"
              ((howmanyGET++))
          else
              echo "no"
          fi
      done < transfer.log
      
      echo "GET: $howmanyGET"
      echo "loop: $loopcounter"
      

      在这里输出:

      $ bash counter.sh 
      GET
      yes
      GET
      yes
      GET
      yes
      GET
      yes
      GET
      yes
      POS
      no
      GET: 5
      loop: 6
      

      希望对您有所帮助。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-05-21
        • 2017-05-05
        • 2018-08-28
        • 1970-01-01
        相关资源
        最近更新 更多