Bash 用引号分析字符串

Bash 用引号分析字符串,bash,Bash,我正在尝试从http日志文件检索主机。 通常,我会这样做: cat proxy.log | awk '{ print $16 }' 但是,日志文件的格式如下: 2012-05-21 05:55:01 503 <client_ip> - - - OBSERVED "Entertainment" - 200 TCP_RESCAN_HIT GET text/xml;%20charset=UTF-8 http <server_ip> <server_host> 80

我正在尝试从http日志文件检索主机。 通常,我会这样做:

cat proxy.log | awk '{ print $16 }'
但是,日志文件的格式如下:

2012-05-21 05:55:01 503 <client_ip> - - - OBSERVED "Entertainment" - 200 TCP_RESCAN_HIT GET text/xml;%20charset=UTF-8 http <server_ip> <server_host> 80 / ?feed=rss2 - "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; InfoPath.3; MS-RTC LM 8; Microsoft Outlook 14.0.6025; ms-office; MSOffice 14)" <proxy_ip> 13356 479 -
$ cat proxy.log
2012-05-21 05:55:01 503 <client_ip> - - - OBSERVED "Entertainment" - 200 TCP_RESCAN_HIT GET text/xml;%20charset=UTF-8 http <server_ip> <server_host> 80 / ?feed=rss2 - "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; InfoPath.3; MS-RTC LM 8; Microsoft Outlook 14.0.6025; ms-office; MSOffice 14)" <proxy_ip> 13356 479 -
$ cat proxy.log | sed -r 's/^.*(GET|POST) [^ ]+ http ([^ ]+) .*$/\2/'
<server_ip>
2012-05-21 05:55:01 503----观察到的“娱乐”-200 TCP重新扫描命中获取文本/xml;%20charset=UTF-8 http 80/?feed=rss2-“Mozilla/4.0(兼容;MSIE 7.0;Windows NT 6.1;WOW64;Trident/4.0;SLCC2;.NET CLR 2.0.50727;.NET CLR 3.5.30729;.NET CLR 3.0.30729;Media Center PC 6.0;.NET4.0E;InfoPath.3;MS-RTC LM 8;Microsoft Outlook 14.0.6025;MS office;MSOffice 14)”13356479-
正如您所看到的,一些字段被引用,并且具有动态的空白量。这意味着$16并不总是返回主机。 我可以使用返回数组的shlex.split()在python中解决这个问题

但是,我使用的一些系统没有安装python,我想知道这如何使bash脚本(带有标准gnu工具)以我可以一致处理的方式分割日志条目,即16美元

如果读者有相同的问题,并且有可用的python,下面是我的python解决方案:

#!/usr/bin/env python

import shlex, sys, string
EOF = ""
if len(sys.argv) == 2:
        try:
                field = int(sys.argv[1])
        except ValueError:
                print "error: <field_no> must be a positive integer"
                sys.exit(1)
else:
        print "usage: %s <field_no>" % sys.argv[0]
        sys.exit(1)

def process(line):
        line = string.strip(line)
        line = shlex.split(line)
        return line[int(sys.argv[1])]

line = sys.stdin.readline()
while not line == EOF:
        sys.stdout.write(process(line)+"\n")
        line = sys.stdin.readline()
#/usr/bin/env python
导入shlex、sys、字符串
EOF=“”
如果len(sys.argv)==2:
尝试:
field=int(sys.argv[1])
除值错误外:
打印“错误:必须是正整数”
系统出口(1)
其他:
打印“用法:%s”%sys.argv[0]
系统出口(1)
def流程(生产线):
行=字符串。条带(行)
line=shlex.split(行)
返回行[int(sys.argv[1])]
line=sys.stdin.readline()
虽然不是直线==EOF:
sys.stdout.write(进程(行)+“\n”)
line=sys.stdin.readline()
如果
GET(something)http
位是可靠的,您可以像这样使用GNU-sed:

2012-05-21 05:55:01 503 <client_ip> - - - OBSERVED "Entertainment" - 200 TCP_RESCAN_HIT GET text/xml;%20charset=UTF-8 http <server_ip> <server_host> 80 / ?feed=rss2 - "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; InfoPath.3; MS-RTC LM 8; Microsoft Outlook 14.0.6025; ms-office; MSOffice 14)" <proxy_ip> 13356 479 -
$ cat proxy.log
2012-05-21 05:55:01 503 <client_ip> - - - OBSERVED "Entertainment" - 200 TCP_RESCAN_HIT GET text/xml;%20charset=UTF-8 http <server_ip> <server_host> 80 / ?feed=rss2 - "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; InfoPath.3; MS-RTC LM 8; Microsoft Outlook 14.0.6025; ms-office; MSOffice 14)" <proxy_ip> 13356 479 -
$ cat proxy.log | sed -r 's/^.*(GET|POST) [^ ]+ http ([^ ]+) .*$/\2/'
<server_ip>
$cat proxy.log
2012-05-21 05:55:01 503----观察到的“娱乐”-200 TCP重新扫描命中获取文本/xml;%20charset=UTF-8 http 80/?feed=rss2-“Mozilla/4.0(兼容;MSIE 7.0;Windows NT 6.1;WOW64;Trident/4.0;SLCC2;.NET CLR 2.0.50727;.NET CLR 3.5.30729;.NET CLR 3.0.30729;Media Center PC 6.0;.NET4.0E;InfoPath.3;MS-RTC LM 8;Microsoft Outlook 14.0.6025;MS office;MSOffice 14)”13356479-
$cat proxy.log | sed-r's/^.*(GET | POST)[^]+http([^]+).$/\2/'

如果您只想去掉可变数量的空格,可以在awk之前使用sed

cat proxy.log | sed 's/  */ /g' | awk '{ print $16 }'

使用替换s/*//g时,任何正数的空格都被剥离为一个

我会尝试匹配一个字段,其中前一个字段是IP地址,下一个字段是整数:

perl -MRegexp::Common -ane '
  $n=16;
  while ($n < @F) {
    if ($F[$n-2] =~ /$RE{net}{IPv4}/ and $F[$n] =~ /^\d+$/)
      print "$F[$n-1]\n";
      break;
    }
    $n++;
  }
' filename
perl-MRegexp::Common-ane'
$n=16;
而($n<@F){
如果($F[$n-2]=~/$RE{net}{IPv4}/和$F[$n]=~/^\d+$/)
打印“$F[$n-1]\n”;
打破
}
$n++;
}
'文件名

在本例中,哪一个是主机名,您能否从行尾识别主机名(它将出现在什么位置或标记处)?回答得很好,但此查询可能会出现一些问题。您有http命令跟踪、选项等。。。也要考虑。它可能是http以外的另一种传输方式(https,gopher?!)。唯一保持不变的是字段的数量,如果可以包含空格,则封装在“”中。对不起,这不太管用。“娱乐”也可以是“娱乐、电脑和互联网”。我想做的是,把它放在数组中,比如说,9美元是“娱乐、计算机和互联网”,我想你可以试试“替换所有空白,之前有奇数引号的空白”,但我想不出一种方法来使用sed。perl可以做到这一点