Объединение «таблиц» с awk

#awk

#awk

Вопрос:

У меня есть несколько «таблиц» в файле, например:

 col1, col2, col3, col4
1, 2, 3, 4
5, 6, 7, 8

col2, col3, col5
10, 11, 12
13, 14, 15
  

И я хотел бы свернуть эти 2 таблицы, чтобы:

 col1, col2, col3, col4, col5
1   , 2   , 3   , 4   , 
5   , 6   , 7   , 8   , 
    , 10  , 11  ,     , 12
    , 13  , 14  ,     , 15
  

(Примечание: дополнительные пробелы оставлены только для упрощения понимания)

Казалось бы, для этого требуется как минимум 2 прохода: один для сбора полного списка столбцов, а другой для создания выходной таблицы. Возможно ли это сделать с помощью awk? Если нет, какой другой инструмент вы бы порекомендовали?

Комментарии:

1. одним из решений было бы создать file2 с уже имеющимися пустыми столбцами, тогда проблема намного проще, ИНАЧЕ вы хотите, чтобы это было динамическим и имело логику, которая считывает заголовок ‘col1, ol2 …’, находя общие столбцы? Удачи

2. Команда join (1) делает почти то, что вы хотите. Вы можете попробовать написать сценарий awk для чтения файла, определения групп столбцов, записи их в два отдельных файла и создания командной строки join.

Ответ №1:

попробуйте это:

Код:

 $ cat s.awk
NR==FNR{
    if (match($1, /^col/))
        maxIndex=(substr($NF,4,1)>maxIndex)?substr($NF,4,1):maxColumn
    next
}

FNR==1{
    for (i=1;i<=maxIndex;i  )
        header=(i==maxIndex)?header "col"i:header "col" i ", "
    print header
}

/^col[1-9]/{
    for (i in places)
        delete places[i]
    for (i=1;i<=NF;i  ){
        n=substr($i,4,1)
        places[n]=i
    }
}

/^[0-9]/{
    s=""
    for (i=1;i<=maxIndex;i  )
        s=(i in places)? s $places[i] " " : s ", "
    print s
}
  

Вызов с:

 awk -f s.awk file file  | column -t
  

Вывод:

 col1,  col2,  col3,  col4,  col5
1,     2,     3,     4      ,
5,     6,     7,     8      ,
,      10,    11,    ,      12
,      13,    14,    ,      15
  

HTH Крис

Комментарии:

1. Это работало бы прекрасно, если бы только заголовки моих столбцов были так красиво названы. Я не должен был называть их так, как я это сделал, поскольку это создавало впечатление, что в их именах был шаблон. Есть идеи относительно того, что делать, если имена столбцов в значительной степени случайны?

2. Пожалуйста, приведите нам конкретные примеры того, что у вас есть и чего вы хотите. Довольно много случайного так же конкретно, как и почти все.

3. Или вы могли бы предварительно обработать свои данные. На первом шаге создайте сопоставление имен ваших столбцов с именами в стиле «colX». Затем используйте awk / sed для переименования имен столбцов и, наконец, запустите мой скрипт.

4. Лучший образец столбцов для таблицы 1: «имя, адрес, возраст, любимый цвет», а для таблицы 2: «имя, адрес, рост». Т.Е. Имена столбцов не имеют шаблона.

Ответ №2:

В коде предполагается, что таблицы разделены пустыми строками:

 awk -F', *' 'END {
  for (i = 0;   i <= c;)
    printf "%s", (cols[i] (i < c ? OFS : RS))
  for (i = 0;   i <= n;)
    for (j = 0;   j <= c;)
      printf "%s", (vals[i, cols[j]] (j < c ? OFS : RS))    
  }
!NF { 
  fnr = NR   1; next 
  }
NR == 1 || NR == fnr  {
 for (i = 0;   i <= NF;) {
   _[$i]   || cols[  c] = $i
   idx[i] = $i
   }
  next 
  }
{  
    n; for (i = 0;   i <= NF;)
         vals[n, idx[i]] = $i
   }' OFS=', ' tables
  

Если у вас есть таблицы в отдельных файлах:

 awk -F', *' 'END {
  for (i = 0;   i <= c;)
    printf "%s", (cols[i] (i < c ? OFS : RS))
  for (i = 0;   i <= n;)
    for (j = 0;   j <= c;)
      printf "%s", (vals[i, cols[j]] (j < c ? OFS : RS))    
  }
FNR == 1 {
 for (i = 0;   i <= NF;) {
   _[$i]   || cols[  c] = $i
   idx[i] = $i
   }
  next 
  }
{  
    n; for (i = 0;   i <= NF;)
         vals[n, idx[i]] = $i
   }' OFS=', ' file1 file2 [.. filen] 
  

Ответ №3:

Вот однопроходное решение perl. Предполагается, что между каждой таблицей в файле есть хотя бы одна пустая строка.

 perl -00 -ne '
    BEGIN {
        %column2idx = ();
        @idx2column = ();
        $lineno = 0;
        @lines = ();
    }

    chomp;
    @rows = split /n/;

    @field_map = ();
    @F = split /, /, $rows[0];
    for ($i=0; $i < @F; $i  ) {
        if (not exists $column2idx{$F[$i]}) {
            $idx = @idx2column;
            $column2idx{$F[$i]} = $idx;
            $idx2column[$idx] = $F[$i];
        }
        $field_map[$i] = $column2idx{$F[$i]};
    }

    for ($i=1; $i < @rows; $i  ) {
        @{$lines[$lineno]} = ();
        @F = split /, /, $rows[$i];
        for ($j=0; $j < @F; $j  ) {
            $lines[$lineno][$field_map[$j]] = $F[$j];
        }
        $lineno  ;
    }

    END {
        $ncols = @idx2column;
        print join(", ", @idx2column), "n";

        foreach $row (@lines) {
            @row = ();
            for ($i=0; $i < $ncols; $i  ) {
                push @row, $row->[$i];
            }
            print join(", ", @row), "n";
        }
    }
' tables | column -t
  

вывод

 col1,  col2,  col3,  col4,  col5
1,     2,     3,     4,
5,     6,     7,     8,
,      10,    11,    ,      12
,      13,    14,    ,      15
  

Комментарии:

1. Это не будет работать для файлов, которые начинаются с «col2, col3, col5», за которыми следует «col1, col2, col3, col4». (обратная сторона примера)

2. Я предполагал, что заголовки столбцов могут быть любыми произвольными именами, такими как «first, last, phone, addr, …» и не обязательно пронумерованы.

3. Кстати, это действительно работает, столбцы в выходных данных следующие: «col2, col3, col5, col1, col4»