У меня есть 4 tsv-файла (разделенные табуляцией), которые выглядят следующим образом:
файл_1:
abc 1
def 2
ghi 3
файл_2:
abc 2
ghi 3
файл_3:
def 1
ghi 2
jkl 4
файл_4:
ghi 3
jkl 4
Я хочу объединить эти файлы, чтобы получить один tsv-файл, например:
dataset file_1 file_2 file_3 file_4
abc 1 2
def 2 4
ghi 3 3 2 3
jkl 4 4
Я пробовал использоватьawk
$ awk '
BEGIN{OFS=FS="\t"}
FNR==1{f = f "\t" FILENAME}
NR==FNR{a[$1] = $2}
NR!=FNR{a[$1] = a[$1] "\t" $2}
END{printf "dataset%s\n", f; for(i in a) print i, a[i]}
' file_{1..4}
Эта команда работает, но я получил смещенное значение. Допустим, если первый и второй столбец имеют пустое значение, а третий и четвертый столбцы имеют значение 4 и 4, вывод, который я получил от этой команды, для первого и второго столбца имеет значение 4, но для третьего и четвертого столбца имеют пустое значение. Поэтому я пытаюсь объединить свой tsv-файл отдельно, используя awk
то, что я упомянул. Сначала только для file_1
и file_2
для получения output_1
, затем объединяю file_3
и file_4
для получения output_2
. После этого я использую $ join output_1 output_2
для объединения output_1 и output_2, но получаю только значения, которые существуют в 4 файлах. Я потерял данные, которые существуют только в одном файле.
Я буду очень признателен, если вы дадите мне совет.
Спасибо
решение1
$ cat tst.awk
BEGIN { FS=OFS="\t" }
{ datasets[$1]; fnames[FILENAME]; vals[$1,FILENAME] = $2 }
END {
printf "%s", "dataset"
for (fname in fnames) {
printf "%s%s", OFS, fname
}
print ""
for (dataset in datasets) {
printf "%s", dataset
for (fname in fnames) {
printf "%s%s", OFS, vals[dataset,fname]
}
print ""
}
}
$ tail -n +1 file?
==> file1 <==
a 1
b 2
c 3
==> file2 <==
a 2
c 3
$ awk -f tst.awk file1 file2
dataset file1 file2
a 1 2
b 2
c 3 3
Добавьте в список столько файлов, сколько захотите.
решение2
С помощью join (GNU coreutils) 8.30
и «замены процесса» вы можете попробовать
join -a1 -a2 -t" " -oauto -e " " <(join -a1 -a2 -t" " -oauto -e "" file[12]) <(join -a1 -a2 -t" " -oauto -e " " file[34])
abc 1 2
def 2 1
ghi 3 3 2 3
jkl 4 4
Параметры -t
имеют <TAB>
символьное значение.
решение3
Совет на данный момент: если понадобится, используйте код позже.
Я бы сохранил три массива, пока вы читаете все файлы.
(a) Для каждого нового файла — хэш-список имен файлов.
(b) Для каждого нового набора данных — хэш-список из $1.
(c) Для каждой строки — хэш-список значений.
FNR == 1 { ++htFile[FILENAME]; }
! ($1 in htSet) { ++htSet[$1]; }
{ htVal [FILENAME, $1] = $2; }
В функции End выполните итерацию по htFile и htSet.
function Table (r, c, buf) {
buf = "dataset";
for (c in htFile)
buf = sprint ("%s\t%s", buf, htFile[c]);
print buf;
for (r in htSet) {
buf = "";
for (c in htFile)
buf = sprint ("%s\t%s", buf, htVal[c, r]);
print substr (buf, 2);
}
}
END { Table( ); }
Это не сохраняет порядок файлов и наборов данных в выходной таблице. Если это имеет значение, вы можете сохранить упорядоченную версию таблиц и выполнить итерацию в исходном порядке.