получить значения по списку колонок в unix

У меня есть файл1:

col1=val1|col2=val2|col3=val3|col4=val4
col1=val1|col2=val2|col4=val4|col5=val5|col6=val6
col1=val1|col3=val3|col4=val4|col6=val6
col1=val1|col2=val2|col3=val3|col4=val4|col5=val5|col6=val6

И уникальный список столбцов в файле2:

col1
col2
col3
col4
col5
col6

В соответствии с последовательностью столбцов файла2 мне нужно получить их значение из файла1 в отдельный файл, используя разделители pipe.

выход выглядит так:

val1|val2|val3|val4|||
val1|val2||val4|val5|val6
val1||val3|val4||val6
val1|val2|val3|val4|val5|val6
0
21.11.2018, 10:34
4 ответа

В любом случае, когда у вас есть входные данные с парами имя=значение, лучший подход - сначала создать массив имя->значение, а затем вывести содержимое этого массива по именованным индексам. В данном случае порядок этих имен взят из другого файла, поэтому сначала прочитайте его:

$ cat tst.awk
BEGIN { FS="[=|]"; OFS="|" }
NR==FNR { outFldNames[++numOutFlds]=$0; next }
{
    delete name2val
    for (inFldNr=1; inFldNr<NF; inFldNr++) {
        name2val[$inFldNr] = $(inFldNr+1)
    }

    for (outFldNr=1; outFldNr<=numOutFlds; outFldNr++) {
        printf "%s%s", name2val[outFldNames[outFldNr]], (outFldNr<numOutFlds ? OFS : ORS)
    }
}

$ awk -f tst.awk file2 file1
val1|val2|val3|val4||
val1|val2||val4|val5|val6
val1||val3|val4||val6
val1|val2|val3|val4|val5|val6
1
28.01.2020, 02:46

Это классический подход к программированию с awk и ручным отображением:

$ awk -F"[=|]" 'NR==FNR{header[++c]=$1;next}\
 {
  record="";
  for (h=1;h<=c;h++) 
    {
      found="*";
      for (field=1;field<=NF;field+=2) \
        {
          if ($field==header[h]) 
             {found=$(field+1);break}
        };
      record=record "|" found;
    }
  print record
 }' file2 file1

#Output:
|val1|val2|val3|val4|*|*
|val1|val2|*|val4|val5|val6
|val1|*|val3|val4|*|val6
|val1|val2|val3|val4|val5|val6

Для другого файла2 - другой порядок столбцов, например

col6
col4
col3
col5
col2
col1

Вывод будет соответствовать следующему:

|*|val4|val3|*|val2|val1
|val6|val4|*|val5|val2|val1
|val6|val4|val3|*|*|val1
|val6|val4|val3|val5|val2|val1
0
28.01.2020, 02:46
perl -wMstrict -Mvars='*A' -lne '
   if ( @ARGV ) { push @A, $_; }
   else {
      my %h = /([^|=]+)=([^|]+)/g;
      $,="|"; print map { $h{$_} // (($_ eq $A[-1]) ? q/|/ : q//) } @A;
   }
' file2 file1

Обратите внимание на первую строку вывода: Здесь 3 трубы. Благодаря чему логика map такова.

output

val1|val2|val3|val4|||
val1|val2||val4|val5|val6
val1||val3|val4||val6
val1|val2|val3|val4|val5|val6
0
28.01.2020, 02:46
$ cat file1
col1=val1|col2=val2|col3=val3|col4=val4
col1=val1|col2=val2|col4=val4|col5=val5|col6=val6
col1=val1|col3=val3|col4=val4|col6=val6
col1=val1|col2=val2|col3=val3|col4=val4|col5=val5|col6=val6

Я изменил файл2, чтобы продемонстрировать, что столбцы, не перечисленные в файле2, опущены:

$ cat file2
col1
col2
col4
col5
col6

Сценарий:

#!/bin/bash
patterns="$(tr '\n' '|' < file2| sed 's/|$//')"

awk -F'|' -v pat="$patterns" '{
  o=0
  for (i=1; i<=6; i++) {
    f=i-o
    split($f,a,"=")
    if ( a[1] ~ i ) {
      if ( a[1] ~ pat ) {
        printf "%s", a[2]
      }
      if (i != 6) {printf "|"}
    } else {
      printf "|"
      o++
    }

  }
  printf "\n"
}' file1

Вывод без значений столбца3:

$ ./script
val1|val2||val4|||
val1|val2||val4|val5|val6
val1|||val4||val6
val1|val2||val4|val5|val6
0
28.01.2020, 02:46

Теги

Похожие вопросы