Файлы в том же порядке
Если можно с уверенностью предположить, что строки в каждом файле имеют одинаковый порядок, то вы можете выполнить работу довольно кратко с помощью:
awk '
FILENAME != oname { FN++; oname = FILENAME }
{ p[FNR] = $1; s[FNR] = $2; e[FNR] = $3; n[FNR] = $4; f[FN,FNR] = $5; N = FNR }
END {
printf("%-8s %-12s %-12s %-4s %-5s %-5s %-5s\n",
"Part", "Start", "End", "Name", "File1", "File2", "File3");
for (i = 1; i <= N; i++)
{
printf("%-8s %-12d %-12d %-4s %-5d %-5d %-5d\n",
p[i], s[i], e[i], n[i], f[1,i], f[2,i], f[3,i]);
}
}' file_1.txt file_2.txt file_3.txt
Первая строка выделяется при запуске нового файла и увеличивает значение переменной FN
(таким образом, строки из файла 1 могут быть помечены FN == 1
и т. Д.). Он записывает имя файла в oname
, чтобы он мог заметить изменения.
Вторая строка работает с каждой строкой данных, сохраняя первые четыре поля в массивах p
, s
, e
, n
(индексируется по номеру записи в текущем файле) и записывает пятое столбец в f
(индексируется FN
и номером записи). Текущий номер записи в текущем файле записывается в N
.
Блок END
печатает заголовок, затем для каждой строки в массиве (индексированный от 1 до N
) печатает различные поля.
Вывод (неудивительно):
Part Start End Name File1 File2 File3
chr1 101845021 101845132 A 0 6 41
chr2 128205033 128205154 B 0 7 41
chr3 128205112 128205223 C 0 7 42
chr4 36259133 36259244 D 0 7 43
chr5 36259333 36259444 E 0 10 47
chr6 25497759 25497870 F 1 11 48
chr7 25497819 25497930 G 1 11 48
chr8 25497869 25497980 H 1 12 49
Файлы в разных порядках
Если вы не можете полагаться на записи в одном и том же порядке в каждом файле, вам придется работать усерднее. Предполагая, что записи в первом файле находятся в требуемом порядке, следующий скрипт организует печать записей в порядке:
awk '
FILENAME != oname { FN++; oname = FILENAME }
{ key = $1 SUBSEP $2 SUBSEP $3 SUBSEP $4
if (FN == 1)
{ p[key] = $1; s[key] = $2; e[key] = $3; n[key] = $4; f[FN,key] = $5; k[FNR] = key; N = FNR }
else
{ if (key in p)
f[FN,key] = $5
else
printf "Unmatched key (%s) in %s\n", key, FILENAME
}
}
END {
printf("%-8s %-12s %-12s %-4s %-5s %-5s %-5s\n",
"Part", "Start", "End", "Name", "File1", "File2", "File3")
for (i = 1; i <= N; i++)
{
key = k[i]
printf("%-8s %-12d %-12d %-4s %-5d %-5d %-5d\n",
p[key], s[key], e[key], n[key], f[1,key], f[2,key], f[3,key])
}
}' "$@"
Это тесно связано с предыдущим сценарием; FN
обработка идентична. Переменная SUBSEP
используется для разделения индексов в многоиндексном массиве. Переменная key
содержит то же значение, которое
генерироваться путем индексации массива z[$1,$2,$3,$4]
.
При работе с первым файлом (FN == 1
) создаются значения в массивах p
, s
, e
, n
, индексированные по key
. Пятый столбец записывается в f
аналогично. Порядок, в котором ключи появляются в файле, записывается в массиве k
, индексируемом номером записи (файла).
Если вы работаете со вторым или третьим файлом, проверьте, известен ли ключ, и сообщите, если он не известен. Предполагая, что это известно, добавьте пятый столбец в f
снова.
Печать аналогична, за исключением того, что она последовательно собирает ключи из k
, а затем печатает соответствующие значения.
С учетом этих файлов:
file_4.txt
chr8 25497869 25497980 H 1
chr7 25497819 25497930 G 1
chr6 25497759 25497870 F 1
chr5 36259333 36259444 E 0
chr4 36259133 36259244 D 0
chr3 128205112 128205223 C 0
chr2 128205033 128205154 B 0
chr1 101845021 101845132 A 0
file_5.txt
chr2 128205033 128205154 B 7
chr8 25497869 25497980 H 12
chr3 128205112 128205223 C 7
chr1 101845021 101845132 A 6
chr6 25497759 25497870 F 11
chr4 36259133 36259244 D 7
chr7 25497819 25497930 G 11
chr5 36259333 36259444 E 10
file_6.txt
chr5 36259333 36259444 E 47
chr4 36259133 36259244 D 43
chr6 25497759 25497870 F 48
chr8 25497869 25497980 H 49
chr2 128205033 128205154 B 41
chr3 128205112 128205223 C 42
chr7 25497819 25497930 G 48
chr1 101845021 101845132 A 41
Скрипт выдает результат:
Part Start End Name File1 File2 File3
chr8 25497869 25497980 H 1 12 49
chr7 25497819 25497930 G 1 11 48
chr6 25497759 25497870 F 1 11 48
chr5 36259333 36259444 E 0 10 47
chr4 36259133 36259244 D 0 7 43
chr3 128205112 128205223 C 0 7 42
chr2 128205033 128205154 B 0 7 41
chr1 101845021 101845132 A 0 6 41
Есть много обстоятельств, что эти сценарии не очень тщательно приспосабливаются. Например, если файлы имеют разную длину; если есть повторяющиеся ключи; если в одном или двух файлах найдены ключи, а в других - нет; если данные пятого столбца не являются числовыми; если второй и третий столбцы не являются числовыми; если есть только два файла или более трех файлов в списке. Проблема «не числовой» на самом деле легко решается; просто используйте %s
вместо %d
. Но сценарии хрупкие. Они работают в показанных экосистемах, но не очень в целом. Необходимые исправления не являются невероятно сложными; тем не менее, их надо кодировать.
Может быть больше или меньше 3 файлов
Расширение предыдущего сценария для обработки произвольного числа файлов и вывода разделенных табуляцией данных вместо форматированных (читаемых) данных не очень сложно.
awk '
FILENAME != oname { FN++; file[FN] = oname = FILENAME }
{ key = $1 SUBSEP $2 SUBSEP $3 SUBSEP $4
if (FN == 1)
{ p[key] = $1; s[key] = $2; e[key] = $3; n[key] = $4; f[FN,key] = $5; k[FNR] = key; N = FNR }
else
{ if (key in p)
f[FN,key] = $5
else
{
printf "Unmatched key (%s) in %s\n", key, FILENAME
exit 1
}
}
}
END {
printf("%s\t%s\t%s\t%s", "Part", "Start", "End", "Name")
for (i = 1; i <= FN; i++) printf("\t%s", file[i]);
print ""
for (i = 1; i <= N; i++)
{
key = k[i]
printf("%s\t%s\t%s\t%s", p[key], s[key], e[key], n[key])
for (j = 1; j <= FN; j++)
printf("\t%s", f[j,key])
print ""
}
}' "$@"
Ключевым моментом является то, что printf
не выводит символ новой строки, если вы не попросите его сделать это, но print
выводит символ новой строки. Код ведет запись фактических имен файлов для использования при распечатке столбцов. Он перебирает массив данных файла, предполагая, что в каждом файле одинаковое количество строк.
Учитывая 6 файлов в качестве входных данных - три исходных файла, копию первого файла в обратном порядке и переставленные копии второго и третьего файлов, выходные данные имеют 6 столбцов дополнительных данных, с идентифицированными столбцами:
Part Start End Name file_1.txt file_2.txt file_3.txt file_4.txt file_5.txt file_6.txt
chr1 101845021 101845132 A 0 6 41 0 6 41
chr2 128205033 128205154 B 0 7 41 0 7 41
chr3 128205112 128205223 C 0 7 42 0 7 42
chr4 36259133 36259244 D 0 7 43 0 7 43
chr5 36259333 36259444 E 0 10 47 0 10 47
chr6 25497759 25497870 F 1 11 48 1 11 48
chr7 25497819 25497930 G 1 11 48 1 11 48
chr8 25497869 25497980 H 1 12 49 1 12 49