Awk добавить еще один столбец 3-й столбец равен строке

У меня есть файл VCF (с разделителями табуляции), где некоторые значения "RPB" пропали во 2-м столбце, и он как бы сдвинул всю строку влево.

У меня есть следующее:

1   AF1=23  AC1=23
2   RPB=123 AF1=23  AC1=23
3   AF1=23  AC1=23

Мне нужно следующее:

1   NULL    AF1=23  AC1=23
2   RPB=123 AF1=23  AC1=23
3   NULL    AF1=23  AC1=23

Я попробовал это, это сработало с треском..:

awk 'if($2="AF1%" {print $1,"\t"NULL"\t", print$2, print$3}' input.vcf > output.vcf

Я должен импортировать этот VCF в MySQL, так что разделение табуляции должно быть сохранено.. любая идея?

4 ответа

Решение
$ awk 'NF<4{sub(/\t/,"&NULL&")}1' file
1       NULL    AF1=23  AC1=23
2       RPB=123 AF1=23  AC1=23
3       NULL    AF1=23  AC1=23

Кстати, вы не слишком далеки от функционального решения своей попытки:

awk 'if($2="AF1%" {print $1,"\t"NULL"\t", print$2, print$3}' input.vcf

Эта минимально измененная версия привела бы к выводу, который вы хотите:

awk '{if($2~/^AF1/) print $1 "\tNULL\t" $2 "\t" $3; else print}' input.vcf

но, как вы можете видеть, это не очень идиоматический подход.

Этот awk one-liner поможет вам:

kent$  awk -F'\t' -v OFS='\t' '!($2~/^RPB=/){$2="NULL\t"$2}7' file
1       NULL    AF1=23  AC1=23
2       RPB=123 AF1=23  AC1=23
3       NULL    AF1=23  AC1=23

На основе входного файла с разделителями табуляции:

awk -v OFS="\t" 'NF==3{$1=$1 OFS "NULL"} 1' input.vcf

где это может быть изменено на следующее, если входной файл не разделен табуляцией:

awk -v OFS="\t" '{$1=$1 (NF==3 ? OFS "NULL" : "")} 1' input.vcf

В любом случае, когда NF==3 первое поле переназначается, чтобы содержать отсутствующие данные. В первом примере, только выходные разделители измененных строк нуждаются в корректировке, но когда данные не разделены табуляцией, каждую строку необходимо "пересчитать" с повторным назначением до 1 который печатает всю строку.

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

ИМХО, вы не должны использовать регулярные выражения, попробуйте это:

#!/bin/bash
cat input.vcf |\
perl -ane '
    BEGIN{$c=0;$max_fields=0}
    $c2=0;
    foreach(@F){
        $a[$c][$c2]=$_;
        if( $c2  > $max_fields ) {
            $max_fields=$c2; 
        }
        $c2++
    }
    $c++;
    END{
        foreach $i (@a){
            while (@$i < $max_fields + 1 ){
                unshift (@$i,"NULL");   
            }  
        }
        foreach $i (@a){
            foreach $x (@$i){
                print $x,"\t";
            }
            print "\n";
        }
    }'

Выход:

bash test.sh 
NULL    AF1=23  AC1=23  
RPB=123 AF1=23  AC1=23  
NULL    AF1=23  AC1=23  

Объяснение:

  1. Приведенный выше код создает 2D-массив (строки / поля)
  2. Он также хранит max_fields
  3. для каждой строки, если число полей меньше, чем max_fields, чем вставить "NULL" в начале строки
Другие вопросы по тегам