Извлечь несколько строк с помощью awk

Я пытаюсь извлечь две строки из каждой строки, некоторые строки не имеют ни одной строки, некоторые строки имеют одну строку.

Мой вход input.txt:

ID=MD001;refer=init;loc=tap2
ID=MD002;Name=Jam;refer=init;loc=tap2
ID=MD003;Name=Jane;Value=vip;refer=init;loc=tap2
ID=MD008;Name=George;product=car;vall=some;Value=vim;refer=init;loc=tap2
ID=MD0010;product=cars;Value=vip4;refer=init;loc=tap2
ID=MD0018;product=cars;
...

Я хочу сопоставить строку «Имя» или / и «Значение», и вывести их в виде:

ID=MD002 Name=Jam
ID=MD003 Name=Jane Value=vip
ID=MD008 Name=George Value=vim
ID=MD0010 Value=vip4

Я старался:

head input.txt | awk '$1 ~ /Name|Value/ {match($1, /(ID=*);.*(Name*);.*(Value.*)/, name); print name[1] name[2] name[3]}'

Но это все печатало. Спасибо за помощь.

Всего 5 ответов


Не могли бы вы попробовать следующее.

awk '
BEGIN{
  FS=";"
}  
  {
  for(i=2;i<=NF;i++){
    if($i~/^Name|^Value/){
      val=(val?val OFS:"")$i
    }
  }
  if(val){
    print $1,val;
  }
  val=""
}
'  Input_file

Вывод будет следующим для показанных образцов.

ID=MD002 Name=Jam
ID=MD003 Name=Jane Value=vip
ID=MD008 Name=George Value=vim
ID=MD0010 Value=vip4

Начните с этого:

$ cat tst.awk
BEGIN { FS="[=;]" }
{
    delete f
    for (i=1; i<NF; i+=2) {
        f[$i] = $i "=" $(i+1)
    }
    print f["ID"], f["Name"], f["Value"]
}

$ awk -f tst.awk file
ID=MD001
ID=MD002 Name=Jam
ID=MD003 Name=Jane Value=vip
ID=MD008 Name=George Value=vim
ID=MD0010  Value=vip4
ID=MD0018

а затем настройте для соответствия (используя оператор in для проверки присутствия), если вы хотите не печатать строки и / или не печатать пропущенные значения:

$ cat tst.awk
BEGIN { FS="[=;]" }
{
    delete f
    for (i=1; i<NF; i+=2) {
        f[$i] = $i "=" $(i+1)
    }

    hit = 0
    out = f["ID"]
    out = out val("Name")
    out = out val("Value")
}
hit { print out }

function val(tag) {
    if (tag in f) {
        hit = 1
        return (OFS f[tag])
    }
}

$ awk -f tst.awk file
ID=MD002 Name=Jam
ID=MD003 Name=Jane Value=vip
ID=MD008 Name=George Value=vim
ID=MD0010 Value=vip4

другой похожий awk

$ awk -F; -v p='(Name|Value)=' '
       $0~p {printf "%s ", $1; 
             for(i=2; i<=NF; i++) if($i~p) printf "%s ", $i; 
             print ""}' file

ID=MD002 Name=Jam
ID=MD003 Name=Jane Value=vip
ID=MD008 Name=George Value=vim
ID=MD0010 Value=vip4

И еще другое:

$ awk -F; '{                                 # set the delim
    for(i=2;i<=NF;i++)                        # looping from the 2nd field
        if($i~/^(Name|Value)/) {              # looking for keywords and if found
           for(i=1;i<=NF;i++)                 # restart loop from beginning
               if($i~/^(Name|Value)/||i==1)   # outputing first field and matches
                   printf "%s ",$i
           print ""                           # newline in the end
           # next                             # breaking from the 1st loop not needed
        }
}' file

Выход:

ID=MD002 Name=Jam 
ID=MD003 Name=Jane Value=vip 
ID=MD008 Name=George Value=vim 
ID=MD0010 Value=vip4 

Это может быть полезно для функции FPAT в awk, где поля определяются их содержимым, а не их разделителями. См. Https://www.gnu.org/software/gawk/manual/html_node/Splitting-By-Content.html.

awk '
    BEGIN {
            FPAT = "(ID=[^;v]+)|(Name=[^;v]+)|(Value=[^;v]+)"
    }

    NF>1 {
            # Only prints lines that have Name and/or Value
            for (i=1; i<NF; i++) {
                    printf $i " "
            }
            print $NF
    }
' file

FPAT определяет 3 возможных поля. Первый (ID=[^;v]+) означает, что он должен начинаться с ID = и сопровождаться хотя бы одним символом, который не является ни точкой с запятой, ни вертикальным пробелом. Следующие два, (Name=[^;v]+) и (Value=[^;v]+) , аналогично означают Name = или Value =, за которыми следует хотя бы один символ, который не является ни точкой с запятой, ни вертикальным пробелом.


Есть идеи?

10000