AWK: 行上のパターンの位置に関係なく、2 つのカスタム フィールド セパレーター間のパターンを抽出するにはどうすればよいでしょうか?

AWK: 行上のパターンの位置に関係なく、2 つのカスタム フィールド セパレーター間のパターンを抽出するにはどうすればよいでしょうか?

以下はファイル内の行の一部です:

LN=FINE FOODS & PHARMACEUTICALS NTM, MIC=XAIM, RIC=FF.MI, SG=MA1

私はタグ「MIC」の値を抽出することに興味があります。つまり、私が望む出力は次のようになります。

XAIM

行全体はかなり長いです:

20200403: #379 IT0005215329 {CU=EUR, GTPID=144115188076657542, II=IT0005215329, IS=18814564, LN=FINE FOODS & PHARMACEUTICALS NTM, MIC=XAIM, RIC=FF.MI, SG=MA1, SN=801670, STY=ORDINARY, TK="0.0002 to 0.1,0.0005 to 0.2,0.001 to 0.5,0.002 to 1,0.005 to 2,0.01 to 5,0.02 to 10,0.05 to 20,0.1 to 50,0.2 to 100,0.5 to 200,1 to 500,2 to 1000,5 to 2000,10 to 5000,20 to 10000,50 to 20000,100 to 50000,200", TS=FF, TY=S, UQ=1}

タグ「MIC」の行上の位置は常に同じではありません。

私はかなりの数のチュートリアルを読みましたが、それらの解決策はすべて、カスタム フィールド セパレーターを作成し、行上のパターンの位置を使用して目的のパターンを抽出することを含んでいるようです。

例えば、私はこのスレッドつまり、次のコードを使用して「MIC」タグから値を抽出しました。

awk 'BEGIN {FS="MIC=|,"} {print $2}' input.txt

次のような出力が得られました:

GTPID=144115188076657542

上記で示した行サンプル全体を確認すると、出力は「=」記号を持つ 2 番目のタグ「GTPID」の値です。最初は、これは{FS="MIC=|,"}「2 つのカスタム フィールド区切り文字を作成します。1 つ目はMIC=、2 つ目は 」という意味だと考えていました。何らかの理由で、この 2 つのフィールド区切り文字の間にあるものはすべて印刷される,と思っていました。{print $2}

しかし、明らかに上記のコードは、行の 2 番目にある記号「=」を含むパターンの値を出力します。

MIC=からまでの間の値を抽出するにはどうすればよいでしょうか,?

答え1

データ内に名前 = 値のペアがある場合は、まずそのマッピングをキャプチャする配列 (f[]下記) を作成し、その後、任意のフィールドに名前でアクセスするのが最適です。例:

$ awk -F'[=,] *' '{for (i=1;i<NF;i+=2) f[$i]=$(i+1); print f["MIC"]}' file
XAIM

テスト値に適応したり、他のフィールドを任意の順序で印刷したりすることがいかに簡単か見てみましょう。

awk -F'[=,] *' '
    { for (i=1;i<NF;i+=2) f[$i]=$(i+1) }
    (f["MIC"] == "XAIM") && (f["LN"] ~ /FOOD/){ print f["SG"], f["RIC"] }
' file
MA1 FF.MI

答え2

$ sed -n 's/.* MIC=\([^,}]*\).*/\1/p' file
XAIM

これは、または文字列sedと一致するために使用され、行全体が文字列に置き換えられます。その他のデータはすべて破棄されます。 MIC=SOMETHING,MIC=SOMETHING}SOMETHING


$ tr ',' '\n' <file | awk -F '=' '$1 == " MIC" { print $2 }'
XAIM

これは最初にすべてのカンマを改行に置き換え、次にフィールド区切り文字として文字awkを使用して実行します=。最初のフィールドが に等しい場合 MIC、2 番目のフィールドが出力されます。


$ awk -F ',' '{ for (i = 1; i <= NF; ++i) if (sub(" MIC=","",$i)) print $i }' file
XAIM

これはawk入力をコンマ区切りのフィールドとしてのみ使用し、扱います。すべてのフィールドを反復処理し、フィールドが文字列 で始まる場合 MIC=、その文字列はフィールドから削除され、残りが出力されます。


ファイルがJSON形式だった場合(データを変換した可能性があります)からほとんどの REST API は JSON 形式のデータを返すため、ある時点で JSON になります。このデータは金融株式市場に関連しているようです):

{
  "CU": "EUR",
  "GTPID": 144115188076657540,
  "II": "IT0005215329",
  "IS": 18814564,
  "LN": "FINE FOODS & PHARMACEUTICALS NTM",
  "MIC": "XAIM",
  "RIC": "FF.MI",
  "SG": "MA1",
  "SN": 801670,
  "STY": "ORDINARY",
  "TK": "0.0002 to 0.1,0.0005 to 0.2,0.001 to 0.5,0.002 to 1,0.005 to 2,0.01 to 5,0.02 to 10,0.05 to 20,0.1 to 50,0.2 to 100,0.5 to 200,1 to 500,2 to 1000,5 to 2000,10 to 5000,20 to 10000,50 to 20000,100 to 50000,200",
  "TS": "FF",
  "TY": "S",
  "UQ": 1
}

そうすればjq最も簡単だったでしょう:

$ jq -r '.MIC' file1
XAIM

答え3

grepを使用しますcut。一致したデータのみをgrep -o取得するには、 を使用し、要求されたフィールドと値を検索します。 をフィールド区切り文字として使用して、それを に入力し、2 番目のフィールドを取得します。ocut=

$ grep -o 'MIC=[^,]*' input | cut -d= -f2
XAIM

ではsed、要求されたフィールド/値のペアを探し、()とを使用して\1一致するサブパターンを抽出します。

$ sed -nE 's/^.*MIC=([^,]+).*$/\1/;p' input
XAIM
# or, alternatively,
$ sed -n 's/^.*MIC=\([^,]*\).*$/\1/;p' input
XAIM

の場合awk、フィールド区切り文字とレコード区切り文字をそれぞれ=とに設定します,。一致するパターンを持つレコードについては、2 番目のフィールド (つまり値) を出力します。

$ awk 'BEGIN { FS="="; RS=","; } $1 ~ /MIC/ { print $2 }' input
XAIM

答え4

指示

 awk -F "," '{for(i=1;i<=NF;i++){if($i ~ /MIC/){gsub(/.*=/,"",$i);print $i}}}' 

ファイル名

出力

XAIM

関連情報