дублирование столбцов с помощью AWK и разделение их табуляцией

Вопрос или проблема

У меня есть большой файл со следующим форматом, разделённым tab:

#CHROM  POS     ID      REF     ALT     QUAL    FILTER  INFO    FORMAT  recombination
chr1    586001  >63041388>63041391      G       A       60      .       AC=80;AF=0.3125;AN=256;AT=>63041388>63041390>63041391,>63041388>63041389>63041391;NS=3;LV=0     GT    1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32|33|34|35|36|37|38|39|40|41|42|43|44|45|46|47|48|49|50|51|52|53|54|55|56|57|58|59|60|61|62|63|64|65|66|67|68|69|70|71|72|73|74|75|76|77|78|79|80|81|82|83|84|85|86|87|88|89|90|91|92|93|94|95|96|97|98|99|100|101|102|103|104|105|106|107|108|109|110|111|112|113|114|115|116|117|118|119|120|121|122|123|124|125|126|127|128|129|130|131|132|133|134|135|136|137|138|139|140|141|142|143|144|145|146|147|148|149|150|151|152|153|154|155|156|157|158|159|160|161|162|163|164|165|166|167|168|169|170|171|172|173|174|175|176|177|178|179|180|181|182|183|184|185|186|187|188|189|190|191|192|193|194|195|196|197|198|199|200|201|202|203|204|205|206|207|208|209|210|211|212|213|214|215|216|217|218|219|220|221|222|223|224|225|226|227|228|229|230|231|232|233|234|235|236|237|238|239|240|241|242|243|244|245|246|247|248|249|250|251|252|253|254

Теперь последний столбец, 10-й по счёту, состоит из множества чисел, разделённых символом |; однако я хочу добиться следующего:

#CHROM  POS     ID      REF     ALT     QUAL    FILTER  INFO    FORMAT  recombination
chr1    586001  >63041388>63041391      G       A       60      .       AC=80;AF=0.3125;AN=256;AT=>63041388>63041390>63041391,>63041388>63041389>63041391;NS=3;LV=0     GT    1|1    2|2    3|3    ...

Мне удалось разделить столбцы с помощью tab, заменив символ |, теперь мне нужно их дублировать и вернуть символ | между числами. Я несколько раз пытался использовать for циклы, но лучшее, что я смог сделать – это напечатать только два столбца вот так:

1    1
2    2
3    3
...

в противном случае, используя printf, я получаю вывод в одну строку, но не могу сохранить счётчик с таким же значением, как в начальном столбце…
Любая помощь будет очень полезна, заранее спасибо!

Это должно сработать:

awk '/^[^#]/{gsub("\\|","\t",$10); gsub("[0-9]+","&|&\t",$10) }1' file.vcf 

Объяснение

  • awk -F '\t' -v OFS='\t': задает разделители полей ввода (-F '\t') и вывода (-v OFS='\t') как табуляцию.
  • /^[^#]/{ ... }: для строк, которые не начинаются с #, т.е. для не заголовочных строк.
  • gsub("\\|","\t",$10);: заменяет все | в 10-м поле на табуляцию.
  • gsub("[0-9]+","&|&\t",$10): теперь заменяет все наборы цифр на сами себя, затем добавляет | и снова самих себя и табуляцию.
    /^[^#]/{ ... }1': стандартное действие awk, когда что-то оценивается как истинное, это напечатать текущую запись (строку), так что этот 1, который всегда оценивается как истинный (не нулевой) и находится вне условия /^[^#]/{}, напечатает каждую строку.

Вот как это выглядит на ваших данных (показаны только первые несколько полей для ясности):

$ awk -F '\t' -v OFS='\t' '/^[^#]/{gsub("\\|","\t",$10); gsub("[0-9]+","&|&\t",$10) }1' file.vcf | cut -f 1-50
#CHROM  POS ID  REF ALT QUAL    FILTER  INFO    FORMAT  recombination
chr1    586001  >63041388>63041391  G   A   60  .   AC=80;AF=0.3125;AN=256;AT=>63041388>63041390>63041391,>63041388>63041389>63041391;NS=3;LV=0 GT  1|1     2|2     3|3     4|4     5|5     6|6     7|7     8|8     9|9     10|10       11|11       12|12       13|13       14|14       15|15       16|16       17|17       18|18       19|19       20|20       21|21

Обратите внимание, что это не является допустимым VCF, и вам также нужно иметь имя образца в заголовке #CHROM для каждого указанного генотипа, чтобы инструменты, предназначенные для обработки VCF, могли корректно с ним работать.

Используя awk:

$ awk -F '\t' -v OFS='\t' '!/^#/{n=split($10,a,/\|/); $10=""; for(i=1;i<=n;i++) $10 = ($10 ? $10 OFS : "") a[i]"|"a[i]}1'
  • Разделитель поля -F и OFS – это выходной разделитель поля, установлены на \t (таб).
  • Поле $10 разбивается на массив a с помощью разделителя |.
  • Затем $10 устанавливается как пустая строка "".
  • После этого $10 восстанавливается с помощью цикла for.
  • 1 всегда истинно и печатает текущую запись. На самом деле, любое значение считается истинным, кроме пустой строки или нуля.

Если вам не мешает лишняя tab в конце записи, то команду можно сократить до $10 = $10 a[i]"|"a[i] OFS.

Ответ или решение

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

Задание

У вас есть файл, который содержит табуляцию в качестве разделителя. В последнем столбце (10-й) находятся числа, разделенные символом |, и ваша цель — создать дубликаты для этих значений с добавлением между ними символа |.

Пример входных данных:

#CHROM  POS     ID      REF     ALT     QUAL    FILTER  INFO    FORMAT  recombination
chr1    586001  >63041388>63041391      G       A       60      .       AC=80;AF=0.3125;AN=256;AT=>63041388>63041390>63041391,>63041388>63041389>63041391;NS=3;LV=0     GT    1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21

Ожидаемый результат:

#CHROM  POS     ID      REF     ALT     QUAL    FILTER  INFO    FORMAT  recombination
chr1    586001  >63041388>63041391      G       A       60      .       AC=80;AF=0.3125;AN=256;AT=>63041388>63041390>63041391,>63041388>63041389>63041391;NS=3;LV=0     GT    1|1     2|2     3|3     4|4     ...

Решение

Вы можете использовать следующую команду AWK для достижения желаемого результата:

awk -F '\t' -v OFS='\t' '!/^#/{n=split($10,a,/\|/); $10=""; for(i=1;i<=n;i++) $10 = ($10 ? $10 OFS : "") a[i]"|"a[i]}1' ваш_файл.vcf

Пояснение к команде:

  1. -F '\t': задает разделитель входных данных как табуляцию.
  2. -v OFS='\t': устанавливает выходной разделитель полей также на табуляцию.
  3. !/^#/: условие, которое гарантирует, что обработка выполняется только для строк, не начинающихся с символа #, т.е. для строк с данными, а не заголовков.
  4. n=split($10,a,/\|/): делит 10-й столбец на массив a, используя | в качестве разделителя. В n сохраняет количество полученных элементов.
  5. $10="": очищает 10-й столбец, чтобы подготовить его к заполнению новыми значениями.
  6. for(i=1;i<=n;i++) ...: цикл, который проходит по всем элементам массива a, создавая дубликаты каждого значения с добавлением | между ними.
  7. 1: всегда истинное выражение, которое побуждает AWK вывести текущую строку.

Обратите внимание

Данное решение в результате добавляет завершающий символ | в конце, что может не всегда соответствовать желаемому формату. Если вас это смущает, вы можете легко изменить конечные условия или дополнительно обработать выходные данные для удаления лишнего символа.

Данная команда позволит вам эффективно обработать файл и вернуть данные в формате, который вы ожидаете, обеспечивая оптимизацию для дальнейшего анализа или использования.

Если у вас возникнут дополнительные вопросы по работе с AWK или обработке текстовых файлов, не стесняйтесь обращаться за дополнительной помощью.

Оцените материал
Добавить комментарий

Капча загружается...