2017-09-08 8 views
1

awkを使用して複数の行から異なる詳細を抽出しようとしています。 しかし、私はテストを実行し、結果の出力を1行に出力しません。AWKを使用して複数の行から情報を抽出

情報は異なるブロックに位置し、私はブロック内の詳細を抽出する必要が..

awk ' 
    TRA TRB TRC 
    /EKYC/{for(i=1; i<10; i++) 
       { (getline p) 
        if (match(p,"TRA")) { print substr(p,4)} 
        if (match(p,"TRB")) { print substr(p,4)} 
        if (match(p,"TRC")) { print substr(p,4)} 
       } 
      } 
    ' inputfile 

ブロックEKYCがあるだろうとコードTRA TRB TRCはEKYCブロック間に配置されます。テキストファイルは、以下のようなものです

サンプル::ブロックごとに1行で

EKYC 
TRA onlyThisTRA1 
TRB onlyThisTRB1 
THR notThis 
EKYC 
TRA onlyThisTRA2 
TRB onlyThisTRB2 
TRC onlyThisTRC2 
EKYC 
NOT 
TRA onlyThisTRA3 
YEH not this 
TRC onlyThisTRC3 

所望の出力..

onlyThisTRA1 onlyThisTRA2 null 
onlyThisTRA2 onlyThisTRB2 onlyThisTRC2 
onlyThisTRA3 null   onlyThisTRC3 
+0

あなたが今まで読んで、それはめったに最善のアプローチません(あるいは、適切なもの)と、多くの注意点がありますように完全に最初http://awk.freeshell.org/AllAboutGetlineを理解することを確認してくださいgetline' '使用して検討している場合は/落ちた –

答えて

1

あなたはこのawkのコマンドを使用することができます使用

awk '/EKYC/{if (tra != "null") print tra, trb, trc; tra=trb=trc="null"; next} 
$1=="TRA"{tra=$2} $1=="TRB"{trb=$2} $1=="TRC"{trc=$2} 
END{print tra, trb, trc}' file 

onlyThisTRA1 onlyThisTRB1 null 
onlyThisTRA2 onlyThisTRB2 onlyThisTRC2 
onlyThisTRA3 null onlyThisTRC3 
+0

@NoelAlexMakumuli:これはうまくいきましたか? – anubhava

+0

それはうまくいった。残念ながら、私は最初の試合後だけに停止する方法を尋ね忘れた..? TRCはEKYCブロック内で2回以上見つけられるので、最初のマッチだけが必要です。 –

1

をawk多次元配列:

awk '/EKYC/ { cnt++;cnt1=0 } $0 != "EKYC" { cnt1++;if ($2 ~ "not") { $2 = "null" } dat[cnt,cnt1]=$2 } END { for (i=1;i<=cnt;i++) { for (p=1;p<=cnt1;p++) { printf "%s\t",dat[i,p] } print "" } }' filename 

EKYCが見えるときに増分cntを設定し、cnt1を再初期化します。カウンタを使用して、2番目にスペース区切りのデータを格納するデータの作成と配列を行います。最後に、多次元配列をループしてデータを印刷します。

1

awkのソリューション:

awk 'function pr(a){ 
     n="null"; tra=a["TRA"]; trb=a["TRB"]; trc=a["TRC"]; 
     printf "%s %s %s\n",(tra)? tra:n,(trb)? trb:n,(trc)? trc:n; delete a 
    } 
    /EKYC/{ if(f){ pr(a); f=0 } } 
    /^TR[ABC]/{ a[$1]=$2; f=1 }END{ pr(a) }' file 

出力:

onlyThisTRA1 onlyThisTRB1 null 
onlyThisTRA2 onlyThisTRB2 onlyThisTRC2 
onlyThisTRA3 null onlyThisTRC3 
1

あなたのデータを持っているとして、あなたが名前と値のペアを持っているときはいつでも、最善のアプローチは、最初にありますそのマッピング(以下n2v[])をキャプチャしている配列を作成し、その名前で値を参照するだけでよい:

$ cat tst.awk 
BEGIN { OFS="\t" } 
/EKYC/ { prt(); next } 
     { n2v[$1] = $2 } 
END { prt() } 
function prt() { if (length(n2v)) print v("TRA"), v("TRB"), v("TRC"); delete n2v } 
function v(n) { return (n in n2v ? n2v[n] : "null") } 

$ awk -f tst.awk file 
onlyThisTRA1 onlyThisTRB1 null 
onlyThisTRA2 onlyThisTRB2 onlyThisTRC2 
onlyThisTRA3 null onlyThisTRC3 

あなたが興味を持っている名前は大文字または小文字のいずれかで正確に1回しか表示されず、データ内の値に基づいて名前が付けられた変数がないことに注意してください。印刷したいprt()関数の中に, v("THC")を追加するだけで、デフォルトのnullの値が1か所に指定されるので、デフォルトを決定するために別のデフォルトアルゴリズムまたは別のアルゴリズムを使用する場合は、v()関数を変更するだけです。

実際にコマンドラインに印刷される名前のリストを受け入れるようにスクリプトを変更するのは簡単だろう:私ができるようにn2v[]は、第2のスクリプトに移入される方法を変更

$ cat tst.awk 
BEGIN { OFS="\t" } 
/EKYC/ { prt(); next } 
     { val=$0; sub(/^[^[:space:]]+[[:space:]]+/,"",val); n2v[$1] = val } 
END { prt() } 
function prt(  nameList,nameNr,numNames) { 
    if (length(n2v)) { 
     numNames = split(names,nameList) 
     for (nameNr=1; nameNr <= numNames; nameNr++) { 
      printf "%s%s", v(nameList[nameNr]), (nameNr<numNames ? OFS : ORS) 
     } 
     delete n2v 
    } 
} 
function v(n) { return (n in n2v ? n2v[n] : "null") } 

$ awk -v names='TRA TRB TRC' -f tst.awk file 
onlyThisTRA1 onlyThisTRB1 null 
onlyThisTRA2 onlyThisTRB2 onlyThisTRC2 
onlyThisTRA3 null onlyThisTRC3 

$ awk -v names='TRA THR TRC YEH' -f tst.awk file 
onlyThisTRA1 notThis null null 
onlyThisTRA2 null onlyThisTRC2 null 
onlyThisTRA3 null onlyThisTRC3 not this 

注意YEHの値(これは私が今印刷しています)がスペースを持っているので、あなたの名前の値の後に空白が現れるようにします。空白がない場合は、その変更は不要で、セパレータがタブの場合は、BEGINセクションにFS="\t"を設定して、変更する必要はありません。

+1

素晴らしい説明をありがとう。私はそれほどAWKの有能ではない、私は最初の項目だけを一致させる必要があります。 TRA、TRB、TRCがEKYCブロック内の任意のポイントで発生した場合、そのことを考慮する必要はありません。どうすれば実現できますか? –

+0

私はあなたが意味することを理解していませんが、 '{n2v [$ 1] = $ 2}'を変更して、最初に '!(n2vの$ 1){n2v [$ 1] = $ 2}あなたが望むことをしていない場合は、質問を更新して要件を明確にし、より良い例を追加してください。 –

関連する問題