у меня есть три подобных файла, они все как это:
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(1) попробуйте:
join fileA fileB | join - fileC
join
(ответ Денниса) лучше, но просто для удовольствия, вот что я придумал в awk
:
awk '{a=$0; getline b <"fileB"; getline c <"fileC"; $0=a" "b" "c; print $1,$2,$4,$6}' <fileA
Обновление: Вопрос был отредактирован, чтобы указать, что все файлы содержат все ключи, поэтому принятый ответ ( 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
на самом деле является символом табуляции , так как это позволяет использовать ноль или более пробелов или табуляции перед ключом и пробел или табуляция для завершения ключа.
Если файлы очень большие, вы можете попробовать использовать ассоциативные массивы в awk
, но, поскольку размер не указан, я бы начал с этого, пока вы не дойдете до точка, где он работает слишком медленно.
Просто добавлю, что для работы соединения входные данные должны быть отсортированы. Это awk-решение должно обрабатывать любое количество входных файлов. Вы также потеряете исходный порядок ключей (вам понадобится больше кода, чтобы сохранить его).
awk 'END {
for (K in k) print K, k[K]
}
{
k[$1] = k[$1] ? k[$1] FS $2 : $2
}' file1 file2 [.. filen]