AWK: como extrair o padrão entre 2 separadores de campos personalizados, independentemente da posição do padrão na linha?

AWK: como extrair o padrão entre 2 separadores de campos personalizados, independentemente da posição do padrão na linha?

Aqui está um fragmento de uma linha no arquivo:

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

Estou interessado em extrair o valor da tag "MIC", ou seja, minha saída desejada é:

XAIM

A linha inteira é bastante longa:

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}

A posição na linha da tag “MIC” nem sempre é a mesma.

Eu li alguns tutoriais e parece que todas as suas soluções envolvem a criação de separadores de campos personalizados e a extração de um padrão desejado usando a posição do padrão na linha.

Por exemplo, tentei seguir o exemplo dado emeste tópico, ou seja, usei este código para extrair o valor da tag "MIC":

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

Eu obtive a seguinte saída:

GTPID=144115188076657542

Se você verificar todo o exemplo de linha que forneci acima, a saída será o valor da segunda tag "GTPID" que possui o símbolo "=". No começo eu estava pensando que isso {FS="MIC=|,"}significava "criar dois separadores de campos personalizados, sendo o primeiro MIC=e o segundo ,e, por algum motivo, eu esperava que isso {print $2}imprimisse o que quer que estivesse entre esses dois separadores de campos.

Mas obviamente o código acima imprime o valor de qualquer padrão que contenha o símbolo "=" que seja o segundo na linha.

Como faço para extrair o valor entre MIC=e ,então?

Responder1

Sempre que você tiver pares nome=valor em seus dados, é melhor primeiro criar um array que capture esse mapeamento ( f[]abaixo) e então você pode acessar os campos que desejar pelo(s) nome(s), por exemplo:

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

Veja como é fácil adaptar-se aos valores de teste, imprimir outros campos em qualquer ordem, etc.:

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

Responder2

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

Isso é usado sedpara corresponder à string  MIC=SOMETHING,ou MIC=SOMETHING}e substitui a linha inteira pela SOMETHINGstring. Todos os outros dados são descartados.


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

Isso primeiro substitui todas as vírgulas por novas linhas e depois é executado awkcom um =caractere como delimitador de campo. Quando o primeiro campo é igual a  MIC, o segundo campo é impresso.


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

Isso apenas usa awke trata a entrada como campos separados por vírgula. Ele itera em todos os campos e, quando um campo começa com string  MIC=, essa string é removida do campo e o restante é impresso.


Se o arquivo estivesse no formato JSON (acho que você pode ter transformado os dadosdeJSON em algum momento, já que a maioria das APIs REST retornam DADOS formatados em JSON, e esses dados parecem estar relacionados aos mercados de ações financeiros):

{
  "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
}

então jqteria sido mais fácil:

$ jq -r '.MIC' file1
XAIM

Responder3

Com grepe cut. Use grep -opara obter oapenas os dados correspondentes, procure o campo e o valor solicitados. Alimente isso para cut, usando =como separador de campo, e pegue o segundo campo:

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

Com sed. Procure o par campo/valor solicitado, use ()e \1para extrair o subpadrão correspondente:

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

Com awk. Defina o separador de campos e o separador de registros como =e ,respectivamente. Para o registro com o padrão correspondente, imprima o segundo campo (ou seja, o valor):

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

Responder4

comando

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

nome do arquivo

saída

XAIM

informação relacionada