I'm looking to subset a standard VCF file to generate one which only includes insertions (i.e. not indels). I can get part of the way there with:bcftools view -v indels <vcf> | awk '{if(length($4) == 1) print}'However this wouldn't catch an insertion that was part of a multi-allelic record with an insertion and deletion, where the reference length would be greater than 1 bp. Potentially then one way to go is a chain of decomposition, normalisation and then the same reference length filtering  surely there's a better way in one of the many VCF manipulation utils?
How can I extract only insertions from a VCF file?
vcf
A one-liner:zcat my.vcf.gz |  perl -ane '$x=0;for $y (split(,,$F[4])){$x=1 if length($y)>length($F[3])}print if /^#/||$x'or equivalentlyzcat my.vcf.gz |  perl -ane '$x=0;map{$x=1 if length>length($F[3])}split(,,$F[4]);print if /^#/||$x'For simple VCF operations, I generally recommend to write a script. This may be faster than those using heavy libraries. With a script, you only parse fields you care about; most libraries unnecessarily parse every field.On a related note, I recommend not to decompose multi-allelic sites unless necessary. Decomposing is tricky, makes VCF harder to parse and to understand and may be a potential source of errors. Here is an example:#CHROM POS ID REF  ALT               QUAL FILTER  INFO  FORMAT  S1  S2  S3  S411     101 .  GCGT G,GCGA,GTGA,CCGT  199  PASS    .     GT      0/1 1/2 2/3 2/4vt decompose+normalize produces the following VCF:#CHROM POS ID REF  ALT QUAL FILTER INFO FORMAT  S1   S2   S3   S411     101 .  GCGT G   199  PASS   .    GT      0/1  1/.  ./.  ./.11     101 .  G    C   199  PASS   .    GT      0/.  ./.  ./.  ./111     102 .  CGT  TGA 199  PASS   .    GT      0/.  ./.  ./1  ./.11     104 .  T    A   199  PASS   .    GT      0/.  ./1  1/.  1/.In theory, you can reconstruct the original VCF from this output. However, it is very challenging for a program to do that. When you compute allele frequency line-by-line, this VCF will give you wrong results. bcftools norm -m- replaces . with 0. You can get a correct ALT allele frequency from the bcftools output, but a wrong REF allele frequency. Furthermore, vt is also imperfect in that CGT=>TGA is not decomposed.My preferred output is:#CHROM POS    ID     REF    ALT    QUAL   FILTER INFO   FORMAT S1     S2     S3     S411     101    .      GCGT   G,<M>  0      .      .      GT     0/1    1/2    2/2    2/211     101    .      G      C,<M>  0      .      .      GT     0/2    2/0    0/0    0/111     102    .      C      T,<M>  0      .      .      GT     0/2    2/0    0/1    0/011     104    .      T      A,<M>  0      .      .      GT     0/2    2/1    1/1    1/0Here we use a symbolic allele <M> to represent another ALT allele. You can calculate the allele frequency by looking at one line, and won't confuse other ALT alleles with REF. bgt can produce such a VCF indirectly. However, it discards all INFO, so is not a practical solution, either.In summary, it is very difficult to decompose multi-allelic sites. When you get decomposing wrong, your downstream analyses may be inaccurate. Decomposition should be used with caution.