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
Объяснение:
- Приведенный выше код создает 2D-массив (строки / поля)
- Он также хранит max_fields
- для каждой строки, если число полей меньше, чем max_fields, чем вставить "NULL" в начале строки