繁体   English   中英

使用 awk 当分隔符不总是相同时提取字符串的最后一部分

[英]Extract last part of the string when separator is not always the same using awk

我有看起来像这样的行的文件。 文件在这里

ID=4;Dbxref=766;Name=LOC2;gene_biotype=protein_coding
ID=5;Dbxref=800;Name=LOC3;gene_biotype=lncRNA
ID=6;Dbxref=900;Name=LOC4;gene_biotype=protein_coding;partial=true;start_range=.,338076
ID=7;Dbxref=905;Name=LOC5;gene_biotype=pseudogene;pseudo=true

我试图抓住字符串的最后一部分......但结尾并不总是一致的

我试过了:

while read -r line ; do
        ID=`echo $line | awk -F"ID=" '{print $2}' | awk -F";" '{print $1}'`
        Biotype=`echo $line | awk -F"gene_biotype=" '{print $2}'`
        echo -e $ID"\t"$Biotype >> file.txt

done << (grep $'\tgene\t' originalfile.txt)

生物型是不起作用的部分。 理想情况下,输出看起来像

4 protein_coding
5 lncRNA
6 protein_coding;partial=true;start_range=.,338076
7 pseudogene;pseudo=true

我也试过:

    Biotype=`echo $line | awk -F"gene_biotype=" '{print $NF}'`

但它最终什么也没有节省。 任何建议表示赞赏...

使用理解-E的 sed 来使用 ERE(例如 GNU sed 或 OSX/BSD sed):

$ sed -E 's/[^=]*=([^;]*)(;[^;]*){2}[^=]*=/\1\t/' file
4       protein_coding
5       lncRNA
6       protein_coding;partial=true;start_range=.,338076
7       pseudogene;pseudo=true

使用任何 POSIX sed:

$ sed 's/[^=]*=\([^;]*\)\(;[^;]*\)\{2\}[^=]*=/\1\t/' file
4       protein_coding
5       lncRNA
6       protein_coding;partial=true;start_range=.,338076
7       pseudogene;pseudo=true

此外,这里有一种通常使用您将来拥有的 tag=value 数据类型的方法,即首先创建一个数组(下面的f[] )将每个标签/名称映射到它的关联值,然后您就可以访问值按名称进行比较、打印等:

$ cat tst.awk
BEGIN { FS=";"; OFS="\t" }
{
    delete f
    for (i=1; i<=NF; i++) {
        tag = val = $i
        sub(/=.*/,"",tag)
        sub(/[^=]+=/,"",val)
        f[tag] = val
    }
    << do something with "f[tag]"s >>
}

您可以通过以下方式解决您当前的问题:

$ cat tst.awk
BEGIN { FS=";"; OFS="\t" }
{
    delete f
    for (i=1; i<=NF; i++) {
        tag = val = $i
        sub(/=.*/,"",tag)
        sub(/[^=]+=/,"",val)
        f[tag] = val
    }
    sub(/.*;gene_biotype=/,"")
    print f["ID"], $0
}

$ awk -f tst.awk file
4       protein_coding
5       lncRNA
6       protein_coding;partial=true;start_range=.,338076
7       pseudogene;pseudo=true

但是您还可以根据不同值的复合条件包含打印行,以与输入不同的顺序打印列,等等。例如:

$ cat tst.awk
BEGIN { FS=";"; OFS="\t" }
{
    delete f
    for (i=1; i<=NF; i++) {
        tag = val = $i
        sub(/=.*/,"",tag)
        sub(/[^=]+=/,"",val)
        f[tag] = val
    }
}
( (f["Dbxref"] > 800) && (f["partial"] == "true") ) || (f["gene_biotype"] == "protein_coding") {
        print f["Name"], f["ID"]
}

.

$ awk -f tst.awk file
LOC2    4
LOC4    6

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM