0

My problem is similar to this one, but the part I want to extract lies inside the line and I also want to store it in a newly created column in the original file rather than output.

A line in my tab-delimited file looks like:

chr1    25228613        25229157        CDS     HAVANA  .       -       2       ID=CDS:ENST00000338888.3;Parent=ENST00000338888.3;gene_id=ENSG00000020633.18_3;transcript_id=ENST00000338888.3_2;gene_type=protein_coding;gene_name=RUNX3;transcript_type=protein_coding;transcript_name=RUNX3-202;exon_number=7;exon_id=ENSE00001384103.2;level=2;protein_id=ENSP00000343477.3;transcript_support_level=1;tag=basic,appris_alternative_2,CCDS;ccdsid=CCDS30633.1;havana_gene=OTTHUMG00000003316.1_3;havana_transcript=OTTHUMT00000009285.1_2;remap_original_location=chr1:-:24902122-24902666;remap_status=full_contig

I want to extract content behind "gene_name" in $9, this line is RUNX3.

The expected output:

chr1    25228613        25229157        CDS     HAVANA  .       -       2       ID=CDS:ENST00000338888.3;Parent=ENST00000338888.3;gene_id=ENSG00000020633.18_3;transcript_id=ENST00000338888.3_2;gene_type=protein_coding;gene_name=RUNX3;transcript_type=protein_coding;transcript_name=RUNX3-202;exon_number=7;exon_id=ENSE00001384103.2;level=2;protein_id=ENSP00000343477.3;transcript_support_level=1;tag=basic,appris_alternative_2,CCDS;ccdsid=CCDS30633.1;havana_gene=OTTHUMG00000003316.1_3;havana_transcript=OTTHUMT00000009285.1_2;remap_original_location=chr1:-:24902122-24902666;remap_status=full_contig    RUNX3

How to do it using awk or sed?

4 Answers 4

2

Since you know the delimiters then just split and reassemble on those

sed -Ei 's/(.*gene_name=)([^;]*)(;.*)/\1\2\3\t\2/g' gene

which breaks down into

(.*gene_name=)

all of your string up to the gene_name tag goes into variable 1

([^;]*)

all continuous characters up to the ; go into variable 2

(;.*)

the rest of your string goes into variable 3

\1\2\3\t\2

recompose your string with a tab and the gene appended

EDIT

or as @Weijun notes

\0\t\2

Another EDIT

Code golfing

sed -Ei 's/.*gene_name=([^;]*).*/\0\t\1/g' gene
2
  • I think this should meet OP's need for that specific file, but if the matching has to be done over the 9th field (as the OP originally asked), it would involve more work, I believe. Jan 1, 2018 at 8:17
  • True, but this seems like a 'one-shot' fix as repeating data (gene_name) in the same record is not good as a rule.
    – bu5hman
    Jan 1, 2018 at 8:48
1

With gawk:

gawk 'match($9,/^.*gene_name=([^;]*);.*/,arr) {print $0"\t"arr[1]}'

This appends gene_name to the end of each line that contains the "gene_name=" string. You may fine tune it for your needs.

1

Following awk may also help you in same.

awk '{val=$0;sub(/.*gene_name=/,"",val);sub(/\;.*/,"",val);print $0,val}' Input_file
0
1

This is a generic awk solution to parsing out a specific named field out of the attributes field (the 9th tab-delimited field) of a file in the General Feature Format (GFF):

BEGIN { OFS = FS = "\t" }

function get_attrib_by_name(key,  n,attrib,kv) {
    # Split the attribute field on semi-colons.
    n = split($9, attrib, ";")

    # Loop over the attributes and split each on "=".
    # When we've found the one we're looking for (by key name in "key"),
    # return the corresponding value.
    for (i = 1; i <= n; ++i) {
        split(attrib[i], kv, "=")
        if (kv[1] == key) {
            return kv[2]
        }
    }
}

# Using the above function.
{
    name = get_attrib_by_name("gene_name")
    print $0, name
}

This would be used like

$ awk -f script.awk file.gff

where script.awk is the above script.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .