awk-как извлечь шаблон


Запрашивает инструкции по использованию awk для извлечения текстовых блоков с определенными строками из файла.

Файл имеет следующую структуру:

<Information>
<CID>_whole_number_A_</CID>
<string>_text_that_is_not_useful_</string>
<string>_text_that_is_not_useful_</string>
<string>_PATTERN_A_</string>
<string>_text_that_is_not_useful_</string>
</Information>
<Information>
<CID>_whole_number_B_</CID>
<string>_PATTERN_B_</string>
<string>_text_that_is_not_useful_</string>
<string>_text_that_is_not_useful_</string>
<string>_text_that_is_not_useful_</string>
<string>_text_that_is_not_useful_</string>
<string>_text_that_is_not_useful_</string>
</Information>

Хотел бы awk отправить следующий шаблон в новый файл.

<Information>
<CID>_whole_number_A_</CID>
<string>_PATTERN_A_</string>
</Information>
<Information>
<CID>_whole_number_B_</CID>
<string>_PATTERN_B_</string>
</Information>

Примечания к данным:

  • файл содержит 300 000 + элементов CID; каждый идентифицируется с уникальным целым число.
  • паттерны (_PATTERN_A, _PATTERN_B_ и т. д.) есть формат UNII - . Например: UNII-4J4Z8788N8 или UNII-12L95QD6KV.
  • не каждый CID имеет UNII.

Заметки о моем окружении:

  • я работаю под Windows 7 и использую утилиты GnuWin32

Итак, перефразируя по-английски:

В файле FILE_1

Найти каждый CID, который имеет UNII

Отправьте отфильтрованные результаты в FILE_2

Заранее спасибо за инструкции.

========================================================================

Хорошо, я делаю что-то не так.

В моей первой реализации программа возвращает только "запись начинается" и "закрывающий тег", т. е.:

<Information>
</Information>
Вот как я применил ваши инструкции.

Во-первых, я запускаю Windows, поэтому изменил FS= "rn "

Первое регулярное выражение унии, так изменилось к /унии/.

Вторым регулярным выражением является CID, которое вы используется в ваших инструкциях. Там я ничего не менял.

Для второго экземпляра шаблона я изменил значение на / UNII/.

Вот как выглядят мои замены:

BEGIN {
    RS="<Information>"
    FS="rn"
}
/UNII/ {
    print RS
    for (i=1;i<NF;i++) {
        if ($i ~ /CID/ || $i ~ /UNII/) {
            print $i
        }
    }
    print "</Information>"
}

Поскольку я использую Windows, я использую полный путь для выполнения утилит GnuWin32 и чтения/записи данных. Так что мой .файл bat выглядит следующим образом:

C:binawk -f C:binscript.awk < C:UsersOwnerdatainput_file.txt > C:UsersOwnerdataoutput_file.txt

Что я делаю не так?

================================================================================= Вот примерные данные:

<Information>
    <CID>1</CID>
    <Synonym>Acetyl carnitine</Synonym>
    <Synonym>O-Acetyl-L-carnitine</Synonym>
    <Synonym>Ammonium, (3-carboxy-2-hydroxypropyl)trimethyl-, hydroxide, inner salt, acetate, DL-</Synonym>
    <Synonym>UNII-07OP6H4V4A</Synonym>
    <Synonym>_20+_more_</Synonym>
</Information>
<Information>
    <CID>10006</CID>
    <Synonym>HYDANTOIN</Synonym>
    <Synonym>UNII-I6208298TA</Synonym>
    <Synonym>53760_FLUKA</Synonym>
    <Synonym>NSC9226</Synonym>
    <Synonym>_20+_more_</Synonym>
</Information>
<Information>
    <CID>10007</CID>
    <Synonym>Lucofen SA</Synonym>
    <Synonym>461-78-9</Synonym>
    <Synonym>EINECS 207-314-9</Synonym>
    <Synonym>STK664067</Synonym>
    <Synonym>DEA No. 1645</Synonym>
    <Synonym>UNII-NHW07912O7</Synonym>
    <Synonym>CHEMBL1201269</Synonym>
    <Synonym>HMS1376E21</Synonym>
    <Synonym>_20+_more_</Synonym>
</Information>
2 2

2 ответа:

Этот сценарий должен обеспечить хорошую отправную точку:

BEGIN {
    RS="<Information>"
    FS="\n"
}
/UNII/ {
    print RS
    for (i=1;i<NF;i++) {
        if ($i ~ /CID/ || $i ~ /UNII/) {
            print $i
        }
    }
    print "</Information>"
}

Сохранение его в script.awk и запуск его на входе образца производит:

$ awk -f script.awk file
<Information>
    <CID>1</CID>
    <Synonym>UNII-07OP6H4V4A</Synonym>
</Information>
<Information>
    <CID>10006</CID>
    <Synonym>UNII-I6208298TA</Synonym>
</Information>
<Information>
    <CID>10007</CID>
    <Synonym>UNII-NHW07912O7</Synonym>
</Information>

Во-первых, awk-совершенно неправильный инструмент для этого. Но самый простой способ сделать это с awk-подавить линии, которые вы не хотите (вместо того, чтобы выбирать те, которые вы хотите):

/Synonym/ && !/UNII/ { next }
{ print }