awkを使用してgrep -fを再作成する方法

awkを使用してgrep -fを再作成する方法

不要な情報がたくさんある大容量ファイルがあります。私は編集と次の間の部分にのみ興味があり、それを1つの項目として扱います。こうしてフィルタリングしたんだけど..

'

awk  'BEGIN {FS = "\n"; RS = ""; OFS = "\n" ;} {if (/intf/ && /addr/) { print $0"\n"}}' > outputfile

出力ファイルの例は次のとおりです。

edit 114
set uuid 6cb43
set action accept
set srcintf "Port-ch40.1657"
set dstintf "any"
set srcaddr "1.1.1.1"
set dstaddr "all"
set schedule "always"
set service "ALL_ICMP" "icmp-echo-reply" "icmp-source-quench" "icmp-time-exceeded" "icmp-unreachable"
set logtraffic all
next

edit 330
set uuid 6d3d
set action accept
set srcintf "Po40.28"
set dstintf "any"
set srcaddr "all"
set dstaddr "2.2.2.2"
set schedule "always"
set service "ALL_ICMP" "icmp-echo-reply" "icmp-source-quench" "icmp-time-exceeded" "icmp-unreachable"
set logtraffic all
next

grepには、ファイルから値を取得するオプションがあります(grep -f filterfile textfile)。フィルタファイルに値が含まれているとします。

1.1.1.1
3.3.3.3

実際にはもっと多いので、手動で入力するとうまくいかないかもしれません。

awk  'BEGIN {FS = "\n"; RS = ""; OFS = "\n" ;} {if (/intf/ && /addr/ &&(/1.1.1.1/||/3.3.3.3/)) { print $0"\n"}}' > outputfile

ファイルの値を処理するようにawkコマンドを変更できますか?

awk  'BEGIN {FS = "\n"; RS = ""; OFS = "\n" ;} {if (/intf/ && /addr/ &&(values_from_filterfile)) { print $0"\n"}}' > outputfile

答え1

あなたの場合:

awk 'BEGIN {FS = "\n"; RS = ""; OFS = "\n" ;} {if (/intf/ && /addr/ &&(/1.1.1.1/||/3.3.3.3/)) { print $0"\n"}}' > outputfile

これがまさにあなたがしなければならないことです。 1行にいくつかのIPアドレスを含む「match.list」ファイルの内容を次のように比較できます。

gawk '
  ( NR==FNR ) { # NR==FNR only when parsing the first file...
      ipreg=$0; # get one ip from the first file
      gsub(".", "\.", ipreg); #ensure each "." becomes "\." for the regex
      ipreg= "\<" ipreg "\>" # add beginning of word / end of word delimiters
      # that way 1.2.3.4 will NOT match: 11.2.3.42
      ipsreg=ipsreg sep ipreg; sep="|" # add it to the list of ipsreg
      # and sep only added before the 2+ elements as it is an empty string for the 1st
      next # skip everything else, we are parsing the first file...
    }

  
    ( /intf/ && /addr/ && ( $0 ~ ipsreg ) ) # default action will be print $0 if it matches...
    # and as ORS at that point will have been set to "\n\n",
    # it will print the record + an empty line after it
 ' match.list FS="\n" RS="" OFS="\n" ORS="\n\n" - > outputfile
   # the things between match.list and - will be seen as definitions to be done at that time,
   # as they contain a "=", and not be interpreted as filenames
   #  - : is STDIN, and will be the 2nd "file" parsed, where NR>FNR (FNR=for the current file, NR=from the beginning)

答え2

FWIW 私はこれに正規表現を使用しません。以下にラベル(たとえば)を対応する値(たとえば、または)にv[]マップする配列()を作成し、配列インデックスのハッシュ検索を実行してどちらを見つけることができます。現在のブロックに存在する値と目的のタグをラベル付けします。たとえば、POSIX awkを使用すると、次のようになります。srcaddr"1.1.1.1""all"

$ cat tst.awk
NR==FNR {
    ips["\"" $0 "\""]
    next
}
$1 == "edit" {
    lineNr = 1
}
lineNr {
    tagFld = (NF > 2 ? 2 : 1)
    tag = $tagFld
    match($0,"^([[:space:]]*[^[:space:]]+){" tagFld "}[[:space:]]*")
    heads[tag] = substr($0,1,RLENGTH)
    v[tag] = substr($0,RLENGTH+1)
    tags[lineNr++] = tag

    if ( $1 == "next" ) {
        if (    (("srcintf" in v) && (v["srcaddr"] in ips)) \
             || (("dstintf" in v) && (v["dstaddr"] in ips)) \
           ) {
            for ( i=1; i<lineNr; i++ ) {
                tag = tags[i]
                print heads[tag] v[tag]
            }
            print ""
        }
        delete v
        lineNr = 0
    }
}

$ awk -f tst.awk filterfile textfile
edit 114
set uuid 6cb43
set action accept
set srcintf "Port-ch40.1657"
set dstintf "any"
set srcaddr "1.1.1.1"
set dstaddr "all"
set schedule "always"
set service "ALL_ICMP" "icmp-echo-reply" "icmp-source-quench" "icmp-time-exceeded" "icmp-unreachable"
set logtraffic all
next

この構造により、簡単にテストできます。または変更目的のタグの値を指定し、ブロック全体に対して正規表現比較を実行するのではなく、各ブロックの各タグ内容のより正確なテストを作成します。たとえば、is、is、およびincludeブロックを検索または出力したい場合は、次の設定を変更uuidできます6cb43schedulealwaysservice"icmp-time-exceeded"

        if (    (("srcintf" in v) && (v["srcaddr"] in ips)) \
             || (("dstintf" in v) && (v["dstaddr"] in ips)) \

これに関して:

        if (    (v["uuid"] == "6cb43") \
             && (v["schedule"] == "always") \
             && (v["service"] ~ /"icmp-time-exceeded"/) \

印刷前にラベルを異なる値に設定するには、v[]印刷ループの前にラベルを埋めることができます。

$ cat tst.awk
NR==FNR {
    ips["\"" $0 "\""]
    next
}
$1 == "edit" {
    lineNr = 1
}
lineNr {
    tagFld = (NF > 2 ? 2 : 1)
    tag = $tagFld
    match($0,"^([[:space:]]*[^[:space:]]+){" tagFld "}[[:space:]]*")
    heads[tag] = substr($0,1,RLENGTH)
    v[tag] = substr($0,RLENGTH+1)
    tags[lineNr++] = tag

    if ( $1 == "next" ) {
        if (    (("srcintf" in v) && (v["srcaddr"] in ips)) \
             || (("dstintf" in v) && (v["dstaddr"] in ips)) \
           ) {
            v["action"] = "reject"
            v["dstaddr"] = "\"127.0.0.1\""
            for ( i=1; i<lineNr; i++ ) {
                tag = tags[i]
                print heads[tag] v[tag]
            }
            print ""
        }
        delete v
        lineNr = 0
    }
}

$ awk -f tst.awk filterfile textfile
edit 114
set uuid 6cb43
set action reject
set srcintf "Port-ch40.1657"
set dstintf "any"
set srcaddr "1.1.1.1"
set dstaddr "127.0.0.1"
set schedule "always"
set service "ALL_ICMP" "icmp-echo-reply" "icmp-source-quench" "icmp-time-exceeded" "icmp-unreachable"
set logtraffic all
next

答え3

特定の質問にのみ答えてくださいawkはファイルの値を処理できます。getlineはい、ファイル名を使用してコマンド入力をリダイレクトできます<。 BEGINブロックの末尾に以下を追加します。

getline <"filterfile";
fromfilter = $0;
gsub("\n","|",fromfilter);

getlineでファイル全体を読み取るようにFSとRSを設定したので、$0単に行区切り文字を正規表現演算子に置き換えることができます |。結果変数を使用してくださいmatch

if (/intf/ && /addr/ && match($0,fromfilter)) { print $0"\n"}

関連情報