awk: использовать gensub для замены нескольких строк из записи абзаца - PullRequest
0 голосов
/ 25 февраля 2019

У меня есть входной файл с несколькими абзацами, разделенными как минимум двумя новыми строками (\n\n), и я хочу извлечь поля из строк в определенных абзацах.Я думаю, что обработка будет самой простой, если я смогу заставить gensub работать, как я надеюсь.Учитывая следующий входной файл:

[Record R1]
    Var1=0
    Var2=20
    Var3=5

[Record R2]
    Var1=10
    Var3=9
    Var4=/var/tmp/
    Var2=12

[Record R3]
    Var1=2
    Var3=5
    Var5=19

Я хочу напечатать только значение Var2 из записей R1 и R3 (где Var2 на самом деле не существует).Я могу легко сгруппировать все переменные в соответствующие записи, установив RS="\n\n", тогда они все будут содержаться в $0.Но так как я не знаю, где он появится в списке раньше времени, я хочу использовать что-то вроде gensub для его извлечения.Вот что я собираюсь сделать:

awk '
    BEGIN {
        RS="\n\n"
    }
    /Record R1/ || /Record R3/ {
        print gensub(/[\n.]*Var2=(.*)[\n.]*/, "\\1", "g", $0)
    }
' /tmp/input.txt

Но вместо того, чтобы только печатать 20 (значение Var2 из R1), он печатает следующее:

[Record R1]
    Var1=0
    20
    Var3=5
[Record R3]
    Var1=2
    Var3=5
    Var5=19

Намерениечто регулярное выражение в команде gensub будет захватывать все символы (новые строки: \n; и не новые строки: .) до и после Var2=XX и заменять все на XX.Но вместо этого он только захватывает символы в одной строке с Var2=XX.Может ли awk gensub выполнять такую ​​многострочную подстановку?

Я знаю, что альтернативой было бы зациклить все поля в записи, разделив поле, соответствующее Var2=, назнак =, но это менее эффективно, когда я масштабирую его до нескольких переменных.

Ответы [ 2 ]

0 голосов
/ 25 февраля 2019

еще awk

$ awk -v RS= '/\[Record R[13]\]/{for(i=2;i<=NF;i++)
                                   {v=sub(/ *Var2=/,"",$i);
                                    if(v) print $i}}' file

20
0 голосов
/ 25 февраля 2019

Я не понимаю, что вы пытаетесь сделать с помощью gensub (), но делать то, что вы пытаетесь сделать в любом awk, это:

awk -F'[][[:space:]=]+' '{f[$2]=$3} !NF{if (f["Record"]~/^R[12]$/) print f["Var2"]; delete f}' file
20
12

awk -F'[][[:space:]=]+' '{f[$2]=$3} !NF{if (f["Record"]~/^R[13]$/) print f["Var2"]; delete f}' file
20

gensub () не делаетне важно, является ли строка, в которой он работает, одной строкой или несколькими строками. Кстати, \n - это всего лишь еще один символ, ничем не отличающийся от других символов.

Ой, подождите, теперь я вижу, что вы 'вы думаете с этим gensub () - ваши проблемы:

  1. [\n.]* означает zero or more newlines or periods, но у вас нет периодов в вводе, так что это то же самое, что и \n*, но вы нене должно быть никаких новых строк непосредственно перед тем, как Var2
  2. Var2 не существует в ваших 2-х записях, поэтому регулярное выражение не может соответствовать ему.
  3. (.*) будет соответствовать всемудо конца записи (крайние левые самые длинные совпадения).
  4. "g" вводит в заблуждение, поскольку вы ожидаете только 1 совпадение.

Так что использование gensub () для многострочного текстане проблема, ваши регулярные выражения просто ошибочны.

...