Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用Bash解析文件_Bash_Parsing - Fatal编程技术网

使用Bash解析文件

使用Bash解析文件,bash,parsing,Bash,Parsing,我有一个包含多行数据的文件,如下所示: {date=2017-01-01 time=23:59:59 logid=0000000001 srcip=123.123.123.123 srcport=2222 srcintf="Branches_Out" dstip=222.222.222.222 dstport=80 service="tcp/8080" appid=41469 app="Microsoft.Portal" apprisk=elevated applist="default" da

我有一个包含多行数据的文件,如下所示:

{date=2017-01-01 time=23:59:59 logid=0000000001 srcip=123.123.123.123 srcport=2222 srcintf="Branches_Out" dstip=222.222.222.222 dstport=80 service="tcp/8080" appid=41469 app="Microsoft.Portal" apprisk=elevated applist="default"
date=2017-01-01 time=24:00:00 logid=0000000002 srcip=124.124.124.124 srcport=3333 srcintf="Branches_Out" dstip=111.111.111.111 dstport=90 service="tcp/9090" appid=15893 app="HTTP.BROWSER" apprisk=elevated applist="default"}
{123.123.123.123, 222.222.222.222, 80, tcp/8080, "Microsoft.Portal"
124.124.124.124, 111.111.111.111, 90, tcp/9090, "HTTP.BROWSER"}
对于每一行,我需要一个Bash代码来查找
(srcip=,dstip=,dstport=,service=,app=)
之后的特定数据值,并将其解析为新文件,新文件应如下所示:

{date=2017-01-01 time=23:59:59 logid=0000000001 srcip=123.123.123.123 srcport=2222 srcintf="Branches_Out" dstip=222.222.222.222 dstport=80 service="tcp/8080" appid=41469 app="Microsoft.Portal" apprisk=elevated applist="default"
date=2017-01-01 time=24:00:00 logid=0000000002 srcip=124.124.124.124 srcport=3333 srcintf="Branches_Out" dstip=111.111.111.111 dstport=90 service="tcp/9090" appid=15893 app="HTTP.BROWSER" apprisk=elevated applist="default"}
{123.123.123.123, 222.222.222.222, 80, tcp/8080, "Microsoft.Portal"
124.124.124.124, 111.111.111.111, 90, tcp/9090, "HTTP.BROWSER"}

请注意,行大小可能不同,即某些行可能包含更多字段,其他行可能不包含所有字段,即可能不包含
app=

将以下脚本另存为,例如
script.sh

$ cat script.sh

#!/usr/bin/env bash
# add all the keys you need to extract here
keys=(srcip dstip dstport service app)
output=""
while read line; do
    newline=""
    for opt in ${keys[@]}; do
        val="$(echo "$line" | sed -n "s/.*${opt}=\(\S*\).*/\1/p;")"
        if ! [[ -z $val ]]; then
            newline+="$val, "
        fi
    done
    if ! [[ -z $newline ]]; then
        output+="${newline::-2}\n"
    fi  
done <file
if [[ -z $output ]]; then
    echo "nothing extracted!"
    exit 1
fi
echo -e "{${output::-2}}" > extracted.txt    
执行提供输入文件作为第一个参数的脚本:

$ bash script.sh input.txt
这将在工作目录中生成输出文件
extracted.txt

输出文件内容:

$ cat input.txt

{date=2017-01-01 time=23:59:59 logid=0000000001 srcip=123.123.123.123 srcport=2222 srcintf="Branches_Out" dstip=222.222.222.222 dstport=80 service="tcp/8080" appid=41469 app="Microsoft.Portal" apprisk=elevated applist="default"
date=2017-01-01 time=24:00:00 logid=0000000002 srcip=124.124.124.124 srcport=3333 srcintf="Branches_Out" dstip=111.111.111.111 dstport=90 service="tcp/9090" appid=15893 app="HTTP.BROWSER" apprisk=elevated applist="default"}
$ cat extracted.txt

{123.123.123.123, 222.222.222.222, 80, "tcp/8080", "Microsoft.Portal"
124.124.124.124, 111.111.111.111, 90, "tcp/9090", "HTTP.BROWSER"}

将以下脚本另存为,例如,
script.sh

$ cat script.sh

#!/usr/bin/env bash
# add all the keys you need to extract here
keys=(srcip dstip dstport service app)
output=""
while read line; do
    newline=""
    for opt in ${keys[@]}; do
        val="$(echo "$line" | sed -n "s/.*${opt}=\(\S*\).*/\1/p;")"
        if ! [[ -z $val ]]; then
            newline+="$val, "
        fi
    done
    if ! [[ -z $newline ]]; then
        output+="${newline::-2}\n"
    fi  
done <file
if [[ -z $output ]]; then
    echo "nothing extracted!"
    exit 1
fi
echo -e "{${output::-2}}" > extracted.txt    
执行提供输入文件作为第一个参数的脚本:

$ bash script.sh input.txt
这将在工作目录中生成输出文件
extracted.txt

输出文件内容:

$ cat input.txt

{date=2017-01-01 time=23:59:59 logid=0000000001 srcip=123.123.123.123 srcport=2222 srcintf="Branches_Out" dstip=222.222.222.222 dstport=80 service="tcp/8080" appid=41469 app="Microsoft.Portal" apprisk=elevated applist="default"
date=2017-01-01 time=24:00:00 logid=0000000002 srcip=124.124.124.124 srcport=3333 srcintf="Branches_Out" dstip=111.111.111.111 dstport=90 service="tcp/9090" appid=15893 app="HTTP.BROWSER" apprisk=elevated applist="default"}
$ cat extracted.txt

{123.123.123.123, 222.222.222.222, 80, "tcp/8080", "Microsoft.Portal"
124.124.124.124, 111.111.111.111, 90, "tcp/9090", "HTTP.BROWSER"}

你可以用几种不同的方法来做你正在尝试的事情。坚持使用一个简单的
grep-Po
将想要的值分离成
label=value
格式,然后在读取
循环控制
IFS
时,通过添加一个
=
作为分隔符,将
label=value
行管道连接到
,然后允许您使用一个简单的计数器(对于您的
5个术语,计算到
5
),您可以按照所示对其进行格式化

一个简单的脚本可以是:

#!/bin/bash

fname="$1"

test -r "$fname" || {  ## validate filename is readable
    printf "error: file not readable.\nusage: %s filename\n" "${0//*\//}"
    exit 1
}

## use grep -Po to parse into label=value lines
grep -Po 'srcip=[0-9]+[.][0-9]+[.][0-9]+[.][0-9]+|dstip=[0-9]+[.][0-9]+[.][0-9]+[.][0-9]+|dstport=[0-9]+|service="([a-z]+/[0-9]+)"|app="([A-Za-z]+[.][A-Za-z]+)"' "$fname" | 
{
    beg=0
    cnt=0  ## use read with IFS and a counter to parse into CSV
    while IFS="$IFS=" read -r label value; do 
        [ "$beg" -eq '1' ] && [ "$cnt" -eq '0' ] && printf "\n"
        [ "$beg" -eq '0' ] && [ "$cnt" -eq '0' ] && { beg=1; printf "{"; }
        [ "$cnt" -eq '4' ] && printf "%s" "$value" || printf "%s, " "${value//\"/}"

        ((cnt++))
        ((cnt == 5)) && cnt=0
    done
    printf "}\n"
}
输入文件

都在一行上,但在这里分开显示

$ cat zz
{date=2017-01-01 time=23:59:59 logid=0000000001 srcip=123.123.123.123 srcport=2222 
srcintf="Branches_Out" dstip=222.222.222.222 dstport=80 service="tcp/8080" 
appid=41469 app="Microsoft.Portal" apprisk=elevated applist="default" 
date=2017-01-01 time=24:00:00 logid=0000000002 srcip=124.124.124.124 srcport=3333
srcintf="Branches_Out" dstip=111.111.111.111 dstport=90 service="tcp/9090" 
appid=15893 app="HTTP.BROWSER" apprisk=elevated applist="default"}
示例使用/输出

$ bash parselog.sh zz
{123.123.123.123, 222.222.222.222, 80, tcp/8080, "Microsoft.Portal"
124.124.124.124, 111.111.111.111, 90, tcp/9090, "HTTP.BROWSER"}

仔细看一看,让我知道这是否接近你想要达到的目标。

你可以用几种不同的方法来做你正在尝试的事情。坚持一个简单的
grep-Po
将想要的值分离成
label=value
格式,然后在读取
循环c时将
label=value
行输送到
通过添加一个
=
作为分隔符来控制
IFS
,然后允许您使用一个简单的计数器(对
5个术语的
5
),您可以按照所示对其进行格式化

一个简单的脚本可以是:

#!/bin/bash

fname="$1"

test -r "$fname" || {  ## validate filename is readable
    printf "error: file not readable.\nusage: %s filename\n" "${0//*\//}"
    exit 1
}

## use grep -Po to parse into label=value lines
grep -Po 'srcip=[0-9]+[.][0-9]+[.][0-9]+[.][0-9]+|dstip=[0-9]+[.][0-9]+[.][0-9]+[.][0-9]+|dstport=[0-9]+|service="([a-z]+/[0-9]+)"|app="([A-Za-z]+[.][A-Za-z]+)"' "$fname" | 
{
    beg=0
    cnt=0  ## use read with IFS and a counter to parse into CSV
    while IFS="$IFS=" read -r label value; do 
        [ "$beg" -eq '1' ] && [ "$cnt" -eq '0' ] && printf "\n"
        [ "$beg" -eq '0' ] && [ "$cnt" -eq '0' ] && { beg=1; printf "{"; }
        [ "$cnt" -eq '4' ] && printf "%s" "$value" || printf "%s, " "${value//\"/}"

        ((cnt++))
        ((cnt == 5)) && cnt=0
    done
    printf "}\n"
}
输入文件

都在一行上,但在这里分开显示

$ cat zz
{date=2017-01-01 time=23:59:59 logid=0000000001 srcip=123.123.123.123 srcport=2222 
srcintf="Branches_Out" dstip=222.222.222.222 dstport=80 service="tcp/8080" 
appid=41469 app="Microsoft.Portal" apprisk=elevated applist="default" 
date=2017-01-01 time=24:00:00 logid=0000000002 srcip=124.124.124.124 srcport=3333
srcintf="Branches_Out" dstip=111.111.111.111 dstport=90 service="tcp/9090" 
appid=15893 app="HTTP.BROWSER" apprisk=elevated applist="default"}
示例使用/输出

$ bash parselog.sh zz
{123.123.123.123, 222.222.222.222, 80, tcp/8080, "Microsoft.Portal"
124.124.124.124, 111.111.111.111, 90, tcp/9090, "HTTP.BROWSER"}

仔细检查一下,让我知道这是否接近您想要实现的目标。

您可以使用Perl正则表达式来匹配整个模式

 Pattern='{date=(.*?) time=(.*?) logid=(.*?) srcip=(.*?) srcport=(.*?) srcintf=(.*?) dstip=(.*?) dstport=(.*?) service=(.*?) appid=(.*?) app=(.*?) apprisk=(.*?) applist=(.*?)';
然后,在显示时,您可以使用匹配号($1、$2…)替换匹配字符

perl-spe'print s/$Pattern/{$4、$7、$8、$9、$11}/g'

您需要在替换中添加其他匹配号。

您可以使用Perl正则表达式匹配整个模式

 Pattern='{date=(.*?) time=(.*?) logid=(.*?) srcip=(.*?) srcport=(.*?) srcintf=(.*?) dstip=(.*?) dstport=(.*?) service=(.*?) appid=(.*?) app=(.*?) apprisk=(.*?) applist=(.*?)';
然后,在显示时,您可以使用匹配号($1、$2…)替换匹配字符

perl-spe'print s/$Pattern/{$4、$7、$8、$9、$11}/g'
您需要在替换中添加其他匹配号。

在awk中:

$ awk '
BEGIN {                                           # in the beginning
    split("srcip dstip dstport service app",t)    # form wanted keyword list
    for(i in t)
        a[t[i]]
}
{
    for((i=1)&&b="";i<=NF;i++) {                  # check every field
        split($i,k,"=")                           # split on =
        if(k[1] in a)                             # if in keyword list
            b=b (b==""?(NR==1?"{":"\n"):OFS) k[2] # append to buffer
    } 
    printf "%s", b                                # output buffer
}
END {
    print "}"                                     # sugar on the top
}' file
{123.123.123.123 222.222.222.222 80 "tcp/8080" "Microsoft.Portal"
124.124.124.124 111.111.111.111 90 "tcp/9090" "HTTP.BROWSER"}
$awk'
从一开始就开始
拆分(“srcip-dstip-dsport服务应用程序”,t)#表格通缉关键字列表
for(i in t)
a[t[i]]
}
{
对于awk中的((i=1)和&b=“”;i:

$ awk '
BEGIN {                                           # in the beginning
    split("srcip dstip dstport service app",t)    # form wanted keyword list
    for(i in t)
        a[t[i]]
}
{
    for((i=1)&&b="";i<=NF;i++) {                  # check every field
        split($i,k,"=")                           # split on =
        if(k[1] in a)                             # if in keyword list
            b=b (b==""?(NR==1?"{":"\n"):OFS) k[2] # append to buffer
    } 
    printf "%s", b                                # output buffer
}
END {
    print "}"                                     # sugar on the top
}' file
{123.123.123.123 222.222.222.222 80 "tcp/8080" "Microsoft.Portal"
124.124.124.124 111.111.111.111 90 "tcp/9090" "HTTP.BROWSER"}
$awk'
从一开始就开始
拆分(“srcip-dstip-dsport服务应用程序”,t)#表格通缉关键字列表
for(i in t)
a[t[i]]
}
{

对于((i=1)和&b=“”;如果所有行以相同的顺序具有相同的格式术语(5),则iIt可以正常工作,但如果行不是静态的,则如何使其工作,即行可能包含或可能不包含所有5个术语,术语也可能不具有相同的顺序。这将成为一个不同的问题。可以这样做,但必须包含另一个循环,并逐字读取输入。(或者从一组变量术语动态构建正则表达式),然后在一个单独的循环中,根据正则表达式集扫描每个单词以检查是否匹配。如果找到匹配项,则可以将其添加到每行开头未设置的数组中(因此只保存每行找到的匹配项)扫描行中的每个单词后,您可以将数组的内容以CSV格式写出来(处理数量可变的术语)。如果所有行都具有相同的格式术语,则效果良好(5)以相同的顺序,但如果行不是静态的,如何使其工作,即行可能包含也可能不包含所有5个术语,术语也可能不以相同的顺序。这将成为一个不同的问题。可以这样做,但必须包含另一个循环,并逐字读取输入。(或从一组可变术语动态构建正则表达式)然后在一个单独的循环中,根据正则表达式集扫描每个单词以检查是否匹配。如果找到匹配项,则可以将其添加到每行开头未设置的数组中(因此仅保存每行找到的匹配项),然后在扫描行中的每个单词后,可以CSV格式写出数组的内容(处理可变数量的术语)不起作用,似乎val=“$(echo“$line”| sed-n“s/*${opt}=(\s*)./\1/p;”)不正确可能是您做错了什么。我已经用逐步详细信息更新了答案。如果问题仍然存在,请提供您所遇到错误的确切细节。工作正常,Thanx a lot不起作用,似乎val=”$(echo“$line”| sed-n“s/*${opt}=(\s*)./\1/p;”)不正确可能是您做错了什么。我已经用逐步详细的信息更新了答案。如果问题仍然存在,请提供有关您得到的错误的确切详细信息。工作正常,Thanx一个错误行:b=b(b==“”?(NR==1?“{”):OFS)k[2]错误是什么?看看它,
“\n”
应该替换为
ORS
。awk:cmd.line:11:调用未定义的函数那么你在
)前面缺少一个空格;它试图调用不存在的函数
b()
?()
。它的工作非常神奇,我已经在另一个系统及其ru上运行过它