Почему этот шаблон не работает в awk? - PullRequest
0 голосов
/ 18 января 2020

Я пытаюсь распечатать захваченную группу, но awk не удалось ее перехватить. Мой синтаксис регулярных выражений, кажется, ничего плохого. Я что-то пропустил?

Вот текст:

<key>NetworkServices</key>
<dict>
    <key>44412617dfsretret44rewtrtA2</key>
    <dict>
        <key>com.fdgfdgfg.ew3rer.gggfgfdgfg</key>
        <dict>
            <key>endpointProtocols</key>
            <array>
                <string>UDP:443:1450</string>
                <string>TCP:443:1450</string>
            </array>
        </dict>
        <key>DNS</key>
        <dict>
            <key>__INACTIVE__</key>
            <true/>
        </dict>
        <key>UserDefinedName</key>
        <string>4ghgfggfddg</string>
        <key>IPv6</key>
        <dict>
            <key>ConfigMethod</key>
            <string>Automatic</string>
        </dict>
        <key>Interface</key>
        <dict>
            <key>Type</key>
            <string>VPN</string>
        </dict>
        <key>__INACTIVE__</key>
        <true/>
        <key>VPN</key>
        <dict>
            <key>DisconnectOnIdle</key>
            <integer>0</integer>
        </dict>
        <key>IPv4</key>
        <dict>
            <key>ConfigMethod</key>
            <string>VPN</string>
        </dict>
        <key>Proxies</key>
        <dict>
            <key>__INACTIVE__</key>
            <true/>
            <key>FTPPassive</key>
            <integer>1</integer>
        </dict>
    </dict>
    <key>DF6rftr34354tergsdfsdf1D9</key>
    <dict>
        <key>Interface</key>
        <dict>
            <key>Type</key>
            <string>fgfdgfgfgr</string>
            <key>Hardware</key>
            <string>cfghfhgrCenter</string>
            <key>DeviceName</key>
            <string>ip1</string>

А вот мой код:

cat /var/text.txt |  awk 'match($0, /<key>NetworkServices<\/key>.*<key>(.*)<\/key>.*<key>Interface<\/key>.*<\/key>.*<string>ip1<\/string>/) {print substr($0, RSTART+1, RLENGTH-1)}'

Он должен напечатать DF6rftr34354tergsdfsdf1D9, но это не так т.

Заранее спасибо.

Вот проверенный скриншот: enter image description here

Ответы [ 2 ]

1 голос
/ 18 января 2020

Необходимо решить две проблемы: шаблон должен соответствовать целому документу, а шаблон использует группы для выбора значения.

Первая проблема может быть решена путем указания шаблона, который может не существует в данных. Использование «<>» в этом случае. См. Awk для чтения файла целиком для получения дополнительной информации.

Вторая проблема заключается в том, что RSTART, RLENGTH собирают информацию о полном совпадении. Учитывая, что соответствующий шаблон указан группой (в данном случае группа 1), необходима версия соответствия с 3 параметрами, а начальное значение длины должно быть выбрано из данных группы 1. Пример решения использует массив a для сбора информации о группе.

Это будет работать только с GNU awk.

cat /var/text.txt |  awk RS='<>' '
match($0, /<key>NetworkServices<\/key>.*<key>(.*)<\/key>.*<key>Interface<\/key>.*<\/key>.*<string>ip1<\/string>/, a) {
    print substr($0, a[1, "start"], a[1, "length"]) 
}'

В качестве примечания, предлагая (1) сохранять каждый дикт пара ключ / значение в один элемент XML и (2) использование инструмента XML для анализа всего документа. Это облегчит задачу. Например, используя запись Java для записей карты:

<dict>
   <entry>
      <key> key </key>
      <dict>
     </dict>
   </entry>
<dict>
1 голос
/ 18 января 2020

Я не думаю, что awk - правильный инструмент для этого, потому что он предназначен для работы построчно. Поскольку ваш шаблон занимает несколько строк, и у вас есть файл XML, извлеките выгоду из мощной структуры XML.

Итак, если вы хотите напечатать текстовый узел под тегом, который удовлетворяет некоторому условию, выберите его с помощью выражения xpath .

Согласно приведенному выше регулярному выражению, я предполагаю, что вы ищете тег <key>, содержащий текст "NetworkServices", затем вы go переходите к следующему узлу с тегом <dict>, затем вы находите нужный вам узел <key>, запоминаете текст (это то, что вы ищете) и проверяете, что за ним следует <key>Interface</key>, далее вы go переходите к следующему узлу с тегом <dict>, где вы необходимо проверить наличие узла <key>DeviceName</key>, за которым следует <string>ip1</string>.

Вот код, который я бы использовал для выбора с xpath в соответствии с этим:

/usr/bin/xpath -q -e '
  //key[text()="NetworkServices"]/following-sibling::dict[1]
    /key[
      following-sibling::dict[1]/key[
        text()="Interface" and 
        following-sibling::dict[1]/key[
          (text()="DeviceName") and (following-sibling::string[1]/text()="ip1")
        ]
      ]
    ]
    /text()
' input.xml
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...