AWK: как извлечь шаблон между двумя пользовательскими разделителями полей независимо от положения шаблона в строке?

AWK: как извлечь шаблон между двумя пользовательскими разделителями полей независимо от положения шаблона в строке?

Вот фрагмент строки в файле:

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

Если вы проверите весь пример строки, который я привел выше, то увидите, что выводом является значение второго тега «GTPID», в котором есть символ «=». Сначала я подумал, что это {FS="MIC=|,"}означает «создать два пользовательских разделителя полей, первый из которых будет , MIC=а второй — » ,, и по какой-то причине я ожидал, что это {print $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, печатается второе поле.


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

Это использует awkи обрабатывает только ввод как поля, разделенные запятыми. Он выполняет итерацию по всем полям, и когда поле начинается со строки  MIC=, эта строка удаляется из поля, а остаток печатается.


Если бы файл был в формате JSON (я думаю, вы могли преобразовать данныеотJSON в какой-то момент, поскольку большинство REST API возвращают ДАННЫЕ в формате 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для взятия oтолько соответствующих данных, найдите запрошенное поле и значение. Передайте это в cut, используя =в качестве разделителя полей, и возьмите второе поле:

$ 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. Установите разделитель полей и разделитель записей на =и ,соответственно. Для записи с соответствующим шаблоном выведите второе поле (т.е. значение):

$ 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

Связанный контент