объединить 3 файла по первой колонке с помощью join (было awk)? - PullRequest
6 голосов
/ 12 мая 2010

У меня есть три похожих файла, они все такие:

Файл A

ID1 Value1a
ID2 Value2a
  .
  .
  .
IDN Value2n

и я хочу вывод, подобный этому

выход

ID1 Value1a Value1b Value1c
ID2 Value2a Value2b Value2c
.....
IDN ValueNa ValueNb ValueNc

Глядя на первую строку, я хочу, чтобы value1A было значением id1 в fileA, value1B - значением id1 в fileB и т. Д. Для каждого поля и каждой строки. Я думаю, что это как sql join. Я пробовал несколько вещей, но ни одна из них даже близко не была.

РЕДАКТИРОВАТЬ: Все файлы имеют одинаковую длину и идентификаторы.

Ответы [ 4 ]

9 голосов
/ 12 мая 2010

Дай присоединиться (1) попробовать:

join fileA fileB | join - fileC
2 голосов
/ 12 мая 2010

join (ответ Денниса) лучше, но только для пинка, вот что я придумал в awk:

awk '{a=$0; getline b <"fileB"; getline c <"fileC"; $0=a" "b" "c; print $1,$2,$4,$6}' <fileA
2 голосов
/ 12 мая 2010

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


Если вы не слишком обеспокоены производительностью, вы можете попробовать быстрое и грязное:

$ cat file_a
    ID5 Value5a
    ID1 Value1a
    ID3 Value3a
    ID4 Value4a
    ID2 Value2a
$ cat file_b
    ID1 Value1b
    ID3 Value3b
$ cat file_c
    ID2 Value2c
    ID3 Value3c
    ID4 Value4c
    ID5 Value5c
$ cat qq.sh
    #!/bin/bash
    keylist=$(awk '{print $1'} file_[abc] | sort | uniq)
    for key in ${keylist} ; do
        val_a=$(grep "^${key} " file_a | awk '{print $2}') ; val_a=${val_a:--}
        val_b=$(grep "^${key} " file_b | awk '{print $2}') ; val_b=${val_b:--}
        val_c=$(grep "^${key} " file_c | awk '{print $2}') ; val_c=${val_c:--}
        echo ${key} ${val_a} ${val_b} ${val_c}
    done
$ ./qq.sh
    ID1 Value1a Value1b -
    ID2 Value2a - Value2c
    ID3 Value3a Value3b Value3c
    ID4 Value4a - Value4c
    ID5 Value5a - Value5c

Это на самом деле сначала работает с ключами, затем получает значения из каждого файла с этим ключом, или -, если его нет в соответствующем файле.

Команды grep необходимо будет скорректировать, если файл более сложный (либо если поле 1 находится не в начале строки, либо за ним следует разделитель без пробела), но сначала это должно быть разумным решение Вероятность использования grep в этом случае будет:

grep "^[ X]*${key}[ X]"

, где X на самом деле является символом tab , так как это позволяет использовать пробелы или табуляции ноль или более перед клавишей и пробел или табуляцию для завершения клавиши.

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

1 голос
/ 25 июня 2010

Просто добавьте, что для того, чтобы объединение работало, вход должен быть отсортирован. Это решение awk должно обрабатывать любое количество входных файлов. Вы также потеряете исходный порядок ключей (вам потребуется больше кода для его сохранения).

awk 'END {
  for (K in k) print K, k[K]
    }
{ 
  k[$1] = k[$1] ? k[$1] FS $2 : $2 
  }' file1 file2 [.. filen]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...