1

2つのパターンのn番目の出現の間のデータを抽出しようとしています。

パターン1: CardDetail

パターン2: ]

入力ファイルにinput.txtは、各行に含まれる内容が異なる数千行が含まれています。データの取得に関係する行には、常にCardDetail行のどこかに含まれます。を使用して一致する行を見つけるのは簡単ですawkが、各一致間でデータを取得し、それぞれを別々の行に配置することは、私が不足しているところです。

input.txtネットワーク機器および接続されている/子デバイスに関するデータが含まれています。これは次のようになります。

DeviceDetail [baseProductId=router-5000, cardDetail=[CardDetail [baseCardId=router-5000NIC1, cardDescription=Router 5000 NIC, cardSerial=5000NIC1], CardDetail [baseCardId=router-5000NIC2, cardDescription=Router 5000 NIC, cardSerial=5000NIC2]], deviceSerial=5000PRIMARY, deviceDescription=Router 5000 Base Model]
DeviceDetail [baseProductId=router-100, cardDetail=[CardDetail [baseCardId=router-100NIC1, cardDescription=Router 100 NIC, cardSerial=100NIC1], CardDetail [baseCardId=router-100NIC2, cardDescription=Router 100 NIC, cardSerial=100NIC2]], deviceSerial=100PRIMARY, deviceDescription=Router 100 Base Model]

*更新:最初の投稿で、デバイスのPARENTシリアル(deviceSerial)も一緒にリストされている必要があることを忘れました。*

私がどのようoutput.txtに見せたいかは次のようなものです:

"router-5000NIC1","Router 5000 NIC","5000NIC1","5000PRIMARY"
"router-5000NIC2","Router 5000 NIC","5000NIC2","5000PRIMARY"
"router-100NIC1","Router 100 NIC","100NIC1","100PRIMARY"
"router-100NIC2","Router 100 NIC","100NIC2","100PRIMARY"

1つの回線での発生回数はCardDetail、デバイスに応じて0から数百の間で変化する可能性があります。CardDetail発生するたびから次の発生までの間にフィールドごとにすべてのデータを抽出]し、CSV形式で独自の行に転送できるようにする必要があります。

4

4 に答える 4

2

gawkまたはmawkを使用できる場合は、レコードおよびフィールド分割機能を(誤って)使用することでこれを行うことができます。

awk -v RS='CardDetail *\\[' -v FS='[=,]' -v OFS=',' -v q='"' '
  NR > 1 { sub("\\].*", ""); print q $2 q, q $4 q, q $6 q }'

出力:

"router-5000NIC1","Router 5000 NIC","5000NIC1"
"router-5000NIC2","Router 5000 NIC","5000NIC2"
"router-100NIC1","Router 100 NIC","100NIC1"
"router-100NIC2","Router 100 NIC","100NIC2"
于 2013-01-21T21:58:23.357 に答える
1

十分ですか?

$> grep -P -o "(?<=CardDetail).*?(?=\])" input.txt | grep -P -o "(?<=\=).*?(?=\,)"
router-5000NIC1
Router 5000 NIC
router-5000NIC2
Router 5000 NIC
router-100NIC1
Router 100 NIC
router-100NIC2
Router 100 NIC
于 2013-01-21T21:02:07.497 に答える
0

これを試して

 #awk -f myawk.sh temp.txt
 BEGIN { RS="CardDetail"; FS="[=,]"; OFS=","; print "Begin Processing "}
 $0 ~ /baseCardId/ {gsub("]","",$0);print $2, $4 , $6}
 END {print "Process Complete"}
于 2013-01-22T02:46:36.483 に答える
0

以下は、正規表現を使用した例です。テキスト形式に小さな違いがある場合は、これで処理されます。また、これは配列内のすべての値を収集します。必要に応じて、さらに処理 (値の並べ替え、重複の削除など) を行うことができます。

#!/usr/bin/awk -f

BEGIN {
    i_result = 0
    DQUOTE = "\""
}

{
    line = $0
    for (;;)
    {
        i = match(line, /CardDetail \[ **([^]]*) *\]/, a)
        if (0 == i)
            break
        # a[1] has the text from the parentheses
        s = a[1]
        # replace from this: a, b, c   to this:  "a","b","c"
        gsub(/ *, */, "\",\"", s)
        s = DQUOTE s DQUOTE

        results[i_result++] = s
        line = substr(line, RSTART + RLENGTH - 1)
    }
}

END {
    for (i = 0; i < i_result; ++i)
        print results[i]
}

PSただの楽しみのために、Pythonバージョンを作成しました。

#!/usr/bin/python

import re
import sys

DQUOTE = "\""

pat_card = re.compile("CardDetail \[ *([^]]*) *\]")
pat_comma = re.compile(" *, *")

results = []

def collect_cards(line, results):
    while True:
        m = re.search(pat_card, line)
        if not m:
            return
        len_matched = len(m.group(0))
        s = m.group(1)
        s = DQUOTE + re.sub(pat_comma, '","', s) + DQUOTE
        results.append(s)
        line = line[len_matched:]

if __name__ == "__main__":
    for line in sys.stdin:
        collect_cards(line, results)

    for card in results:
        print card

編集:これは、「deviceID」も検索し、一致したテキストを最初のフィールドとして配置する新しいバージョンです。

AWK では、文字列を式の中で隣り合わせにするだけで連結できます。2 つの文字列が並んでいる場合、暗黙的な連結演算子があります。したがって、これは deviceID テキストを s0 という変数に取得し、連結を使用して二重引用符で囲みます。その後、連結を使用して、一致した文字列の先頭に s0 を配置します。

#!/usr/bin/awk -f

BEGIN {
    i_result = 0
    DQUOTE = "\""
    COMMA = ","
}

{
    line = $0
    for (;;)
    {
        i = match(line, /deviceID=([A-Za-z_0-9]*),/, a)
        s0 = DQUOTE a[1] DQUOTE
        i = match(line, /CardDetail \[ **([^]]*) *\]/, a)
        if (0 == i)
            break
        # a[1] has the text from the parentheses
        s = a[1]
        # replace from this: foo=a, bar=b, other=c   to this:  "a","b","c"
        gsub(/[A-Za-z_][^=,]*=/, "", s)
        # replace from this: a, b, c   to this:  "a","b","c"
        gsub(/ *, */, "\",\"", s)
        s = s0 COMMA DQUOTE s DQUOTE

        results[i_result++] = s
        line = substr(line, RSTART + RLENGTH - 1)
    }
}

END {
    for (i = 0; i < i_result; ++i)
        print results[i]
}
于 2013-01-21T22:03:48.867 に答える