Как создать текстовый файл с разделителями-табуляциями со многими вычисленными значениями? - PullRequest
0 голосов
/ 18 июня 2020

Фон

Из набора похожих справочных файлов (sample1.txt, sample2.txt, et c.) Я вычисляю или получаю данные для многих различных параметров (p c .genes , p c .transcripts, p c .genes.antisense, et c.).

Упрощенный пример одиночного ref.file (например, sample1. txt):

word1   word2   word3   405438   409170   .   Y   .   word4; word5
word1   word2   word3   405438   409170   .   N   .   word4; word5
word1   word2   word3   409006   409170   .   N   .   word4; word5
word1   word2   word3   405438   408401   .   Y   .   word4; word5
word1   word2   word3   407099   408361   .   N   0   word4; word5

Расчет для параметра «avg.exons» может выглядеть следующим образом:

$ awk '$3 == "word3"' sample1.txt | sed -n 's/.*word4 \([^;]*\).*word5 \([^;]*\).*/\1;\2/p' | awk -F';' '{a[$1]++}END{for (i in a) {count++; sum += a[i]} print sum/count}'
5.96732

Получение параметра «p c .genes» может выглядят так:

$ awk '$3 == "word3"' sample1.txt | grep -c "word4"
19062

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


Желаемый результат

Я хотел бы поместить эти вычисленные / полученные значения в организованный табличный формат (желательно текстовый файл с разделителями табуляции), чтобы я мог создавать графики из данных:

ref.file    pc.genes    pc.transcripts  pc.genes.antisense  pc.genes.sense  avg.exons   avg.genelength
sample1.txt 19062   116573  2585576 1318321 5.96732 3732.57
sample2.txt 19753   138563  5834759 1433785 5.84654 4023.89
sample3.txt 19376   124576  2871235 1983263 6.78929 3890.32

Возможно ли это? И если да, то как я могу этого добиться?

Попытка

for file in sample*.txt
do
    printf "%s\n" ref.file pc.genes pc.transcripts pc.genes.antisense pc.genes.sense avg.exons avg.genelength | paste -sd $'\t'
    pc.genes=$(awk '$3 == "word3"' ${file} | grep -c "word4")
    avg.exons=$(awk '$3 == "word3"' ${file} | sed -n 's/.*word4 \([^;]*\).*word5 \([^;]*\).*/\1;\2/p' | awk -F';' '{a[$1]++}END{for (i in a) {count++; sum += a[i]} print sum/count}')
    ... # get rest of desired values
done > table.txt

Результирующие ошибки

-bash: pc.genes=19062: command not found
... # other errors with corresponding CORRECT value outputs
-bash: avg.exons=5.96732: command not found
... # the errors even continue into the other sample*.txt files, which is good
-bash: pc.genes=19753: command not found
...

Все значения , соответствующие заданные параметры (например, «=###») верны, но ошибка не позволяет поместить их в таблицу.

Ответы [ 2 ]

1 голос
/ 19 июня 2020

Основываясь исключительно на деталях, предоставленных OP, и предполагая, что конструкция цикла используется для обработки одного файла за раз, что-то вроде:

# print header
printf "ref.file\tpc.genes\tpc.transcripts\tpc.genes.antisense\tpc.genes.sense\tavg.exons\tavg.genelength\n"

while read -r fn
do
    aexons=$(awk '$3 == "word1"' ${fn} | sed -n 's/.*word2 \([^;]*\).*word3 \([^;]*\).*/\1;\2/p' | awk -F';' '{a[$1]++}END{for (i in a) {count++; sum += a[i]} print sum/count}')
    pgenes=$(awk '$3 == "word1"' ${fn} | grep -c "word2")
    ... # get rest of desired values

    # print tab-delimited output to stdout; adjust formats as needed
    printf "%s\t%s\t%s\t%s\t%s\t%s\t%s\n" ${fn} ${pgenes} .... ${axeons} ...

done < <('ls' sample*.txt)  # replace with whatever logic OP is using to find desired files

Хотя приведенное выше должно работать , это не очень эффективно со всеми вызовами подпроцесса ($(...); конвейерные команды) и необходимостью обрабатывать каждый входной файл (${fn}) 6 раз (для значений 6x).

Более Эффективный метод будет рассматривать обработку каждого входного файла (${fn}) только один раз.

Дополнительным шагом может быть устранение l oop в пользу одной программы для обработки всех файлов за один проход.

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

0 голосов
/ 19 июня 2020

Следующий ответ работает отлично и исходит из комбинированных предложений markp-fuso и KamilCuk. Спасибо вам обоим!

# add the table headers
printf "%s\n" ref.file pc.genes pc.transcripts pc.genes.antisense pc.genes.sense avg.exons avg.genelength | paste -sd $'\t'

for file in sample*.txt
do
# create variables containing code for all parameter calculations/retrievals
pcgenes=$(awk '$3 == "word3"' ${file} | grep -c "word4")
pctranscripts=$(...)
pcgenesantisense=$(...)
pcgenessense=$(...)
avgexons=$(awk '$3 == "word3"' ${file} | sed -n 's/.*word4 \([^;]*\).*word5 \([^;]*\).*/\1;\2/p' | awk -F';' '{a[$1]++}END{for (i in a) {count++; sum += a[i]} print sum/count}')
avggenelength=$(...)

# print all resulting values in a single tab separated row of the table
printf "%s\t%s\t%s\t%s\t%s\t%s\t%s\n" ${file} ${pcgenes} ${pctranscripts} ${pcgenesantisense} ${pcgenessense} ${avgexons} ${avggenelength}
done > table.txt
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...