Вопрос или проблема
Привет, у меня есть два файла с одинаковым числом столбцов и строк. Первые 8 столбцов идентичны.
файл1:
chr22 10550966 22:10550966:C:T C T . . . 0.95 0.99 0.99 0.67
chr22 10550966 22:10550966:C:T C T . . . 0 0 0 0
chr22 10550966 22:10550966:C:T C T . . . 0 0 0 0
chr22 10550966 22:10550966:C:T C T . . . 0 0 0 0
chr22 10550966 22:10550966:C:T C T . . . 0.05 0.01 0.01 0.33
файл2:
chr22 10550966 22:10550966:C:T C T . . . 0.97 0.59 0.97 0.88
chr22 10550966 22:10550966:C:T C T . . . 0 0.02 0 0
chr22 10550966 22:10550966:C:T C T . . . 0 0 0.02 0
chr22 10550966 22:10550966:C:T C T . . . 0.02 0.02 0 0.11
chr22 10550966 22:10550966:C:T C T . . . 0 0.37 0 0.01
Как написать скрипт оболочки для выполнения поэлементного сложения между двумя файлами, начиная с 9-го поля до последнего столбца, чтобы получить результат, как в следующем примере:
chr22 10550966 22:10550966:C:T C T . . . 1.92 1.58 1.96 1.55
chr22 10550966 22:10550966:C:T C T . . . 0 0.02 0 0
chr22 10550966 22:10550966:C:T C T . . . 0 0 0.02 0
chr22 10550966 22:10550966:C:T C T . . . 0.02 0.02 0 0.11
chr22 10550966 22:10550966:C:T C T . . . 0.05 0.38 0.01 0.34
С помощью perl
в режиме awk
:
perl -lane '
$_ = <STDIN>; @F2 = split;
$F[$_] += $F2[$_] for 8 .. $#F;
print join "\t", @F' файл1 < файл2
Здесь используется любое количество пробелов в качестве разделителя полей ввода (и игнорируются начальные и конечные пробелы) и TAB в качестве разделителя полей вывода. Для TAB как в качестве входного, так и выходного разделителя полей:
perl -F'\t' -lane '
$_ = <STDIN>; chomp; @F2 = split "\t";
$F[$_] += $F2[$_] for 8 .. $#F;
print join "\t", @F' файл1 < файл2
Обратите внимание на 8 вместо 9, так как perl начинает нумерацию своих элементов массива с 0, а не с 1.
Эквивалент awk
будет выглядеть так:
awk -F'\t' -v OFS='\t' '
{
getline l2 < "file2"; split(l2, f2)
for (i = 9; i <= NF; i++) $i += f2[i]
print
}' файл1
Используя awk
:
awk '
BEGIN{OFS="\t"}
NR==FNR{
a[NR]["c09"]=$9
a[NR]["c10"]=$10
a[NR]["c11"]=$11
next
}
{
$9= a[FNR]["c09"] + $9
$10=a[FNR]["c10"] + $10
$11=a[FNR]["c11"] + $11
print
}
' файл1 файл2
chr22 10550966 22:10550966:C:T C T . . . 1.92 1.58 1.96 0.88
chr22 10550966 22:10550966:C:T C T . . . 0 0.02 0 0
chr22 10550966 22:10550966:C:T C T . . . 0 0 0.02 0
chr22 10550966 22:10550966:C:T C T . . . 0.02 0.02 0 0.11
chr22 10550966 22:10550966:C:T C T . . . 0.05 0.38 0.01 0.01
Позвольте awk
прочитать два файла, размещенных рядом:
$ paste файл1 файл2 | awk '{ print $1, $2, $3, $4, $5, $6, $7, $8, $9+$17, $10+$18, $11+$19, $12+$20 }'
chr22 10550966 22:10550966:C:T C T . . . 0.95 0.99 0.99 0.67
chr22 10550966 22:10550966:C:T C T . . . 0 0 0 0
chr22 10550966 22:10550966:C:T C T . . . 0 0 0 0
chr22 10550966 22:10550966:C:T C T . . . 0 0 0 0
chr22 10550966 22:10550966:C:T C T . . . 0.05 0.01 0.01 0.33
Если ваш ввод разделен табуляцией и ваш вывод также должен быть таким, то задайте FS = OFS = "\t"
в коде awk
:
$ paste файл1 файл2 | awk 'BEGIN { FS=OFS="\t" } { print $1, $2, $3, $4, $5, $6, $7, $8, $9+$17, $10+$18, $11+$19, $12+$20 }'
chr22 10550966 22:10550966:C:T C T . . . 0.95 0.99 0.99 0.67
chr22 10550966 22:10550966:C:T C T . . . 0 0 0 0
chr22 10550966 22:10550966:C:T C T . . . 0 0 0 0
chr22 10550966 22:10550966:C:T C T . . . 0 0 0 0
chr22 10550966 22:10550966:C:T C T . . . 0.05 0.01 0.01 0.33
Ответ или решение
Для решения задачи суммирования значений полей в двух файлах, сохраняя первые 8 полей неизменными, можно воспользоваться командой awk
или perl
. Ниже представлены несколько примеров кода на этих языках.
Условия задачи
У нас есть два файла, file1
и file2
, каждый из которых содержит одинаковое количество строк и одинаковое количество колонок. Первые 8 колонок в обоих файлах идентичны, а начиная с 9-й колонки содержатся числовые значения, которые требуется сложить между файлами. После выполнения операции суммирования, необходимо вывести результат в том же формате, что и исходные файлы.
Пример данных
file1:
chr22 10550966 22:10550966:C:T C T . . . 0.95 0.99 0.99 0.67
chr22 10550966 22:10550966:C:T C T . . . 0 0 0 0
chr22 10550966 22:10550966:C:T C T . . . 0 0 0 0
chr22 10550966 22:10550966:C:T C T . . . 0 0 0 0
chr22 10550966 22:10550966:C:T C T . . . 0.05 0.01 0.01 0.33
file2:
chr22 10550966 22:10550966:C:T C T . . . 0.97 0.59 0.97 0.88
chr22 10550966 22:10550966:C:T C T . . . 0 0.02 0 0
chr22 10550966 22:10550966:C:T C T . . . 0 0 0.02 0
chr22 10550966 22:10550966:C:T C T . . . 0.02 0.02 0 0.11
chr22 10550966 22:10550966:C:T C T . . . 0 0.37 0 0.01
Пример реализации с помощью awk
awk -F'\t' -v OFS='\t' '
{
getline l2 < "file2";
split(l2, f2);
for (i = 9; i <= NF; i++)
$i += f2[i - 8];
print
}' file1
Объяснение кода
-F'\t'
устанавливает разделителем полей символ табуляции.-v OFS='\t'
задаёт символ табуляции как разделитель в выходных данных.getline l2 < "file2"
считывает строку из файлаfile2
.split(l2, f2)
разбивает считанную строку на массивf2
.- Цикл
for (i = 9; i <= NF; i++)
проходит по всем полям, начиная с 9, и выполняет суммирование значений из обоих файлов. print
выводит результат на экран.
Пример реализации с помощью perl
perl -lane '
$_ = <STDIN>;
chomp;
@F2 = split;
for (my $i = 8; $i <= $#F; $i++) {
$F[$i] += $F2[$i];
}
print join("\t", @F);
' file1 < file2
Объяснение кода
-lane
позволяет обрабатывать строки файла в режиме, который разделяет их по пробелам и табуляциям.$_ = <STDIN>
считывает строку из стандартного ввода.@F2 = split
разбивает строку на массив.- Цикл
for
суммирует элементы массива. print join("\t", @F)
выводит итоговую строку в табличном формате.
Заключение
Эти решения дают возможность эффективно выполнять элементное сложение полей в двух файлах, сохраняя при этом первичную структуру данных. Использование awk
или perl
позволяет выбрать наиболее подходящий инструмент в зависимости от предпочтений разработчика.