Linux 命令:从制表符中提取行.其第一列包含特定值的文件



我有一个选项卡消除了txt文件。

exon_id "ENSE00002234944"    exon_number "1"     gene_biotype "pseudogene"   gene_id   "ENSG00000223972"     gene_name "DDX11L1"
gene_biotype "pseudogene"    gene_id "ENSG00000223972"   gene_name "DDX11L1"     gene_source "ensembl_havana"    transcript_id "ENST00000456328"
exon_id "ENSE00002234632"    exon_number "1"     gene_biotype "pseudogene"   gene_id "ENSG00000223972"   gene_name "DDX11L1"
gene_biotype "pseudogene"    gene_id "ENSG00000223972"   gene_name "DDX11L1"     gene_source "ensembl_havana"    transcript_id "ENST00000515242"
exon_id "ENSE00002269724"    exon_number "1"     gene_biotype "pseudogene"   gene_id "ENSG00000223972"   gene_name "DDX11L1"
gene_biotype "pseudogene"    gene_id "ENSG00000223972"   gene_name "DDX11L1"     
gene_biotype "pseudogene"        gene_id "ENSG00000269732"       gene_name "WBP1LP7"         gene_source "havana"    transcript_id "ENST00000437905"
exon_id "ENSE00001687828"        exon_number "1"         gene_biotype "lincRNA"  gene_id "ENSG00000237094"       gene_name "RP4-669L17.10"
gene_biotype "lincRNA"   gene_id "ENSG00000237094"       gene_name "RP4-669L17.10"        gene_source "ensembl_havana"    transcript_id "ENST00000440163"
exon_id "ENSE00001628100"        exon_number "2"         gene_biotype "lincRNA"  gene_id "ENSG00000237094"       gene_name "RP4-669L17.10"
exon_id "ENSE00001770724"        exon_number "3"         gene_biotype "lincRNA"  gene_id "ENSG00000237094"       gene_name "RP4-669L17.10"
exon_id "ENSE00001622961"        exon_number "2"         gene_biotype "lincRNA"  gene_id "ENSG00000237094"       gene_name "RP4-669L17.10"
exon_id "ENSE00002202695"        exon_number "2"         gene_biotype "pseudogene"          gene_id "ENSG00000256186"       gene_name "AL732372.1"
gene_biotype "pseudogene"        gene_id "ENSG00000256186"       gene_name "AL732372.1"    gene_source "ensembl"   transcript_id "ENST00000540477"
exon_id "ENSE00002305101"        exon_number "1"         gene_biotype "pseudogene"         gene_id "ENSG00000256186"       gene_name "AL732372.1"
exon_id "ENSE00001651491"        exon_number "1"         gene_biotype "lincRNA"  gene_id "ENSG00000237094"       gene_name "RP4-669L17.10"

如您所见,每行都有我试图提取的"gene_id"和"gene_name",但列没有对齐。所以我不能用"cut"来做这件事。

实际上,我可以使用 EXCEL 来填充空白字段以对齐和提取我想要的列,但我认为学习它以备将来使用是件好事。

提前谢谢你!

这几乎就是 awk 的目的:

awk '$1 == "gene_biotype" {print $4, $6}' < input.txt

说明:$N表示一个字段,默认情况下用空格分隔。任何空格。相等性检查显示"仅当第一个字段与gene_biotype匹配时才执行行的其余部分"。然后打印相应的字段。如果要删除引号,可以查看gsub函数,也可以超级懒惰并将输出通过管道传输到sed

也许更好的问题是,"我如何正确地规范化这些数据"。 标记的字段格式不适合 TSV(它应该只是制表符分隔的值;键是列索引)。 您可能应该将其转换为与要使用的工具的要求一致的格式。

当键集是静态的、值是简单的非结构化文本或数字,并且大多数值大部分时间都填充时,逗号分隔或制表符分隔的文件是有意义的。

awk -F 't' 'BEGIN { OFS=FS
 f="exon_id:exon_number:gene_biotype:gene_id:gene_name:gene_source:transcript_id"
   n=split(f, field, /:/); for (i=1; i<=n; ++i) key[field[i]]=i }
 { for (i=1; i<=NF; ++i) {
        split($i, v, / /); gsub(/^"|"$/, "", v[2]); value[key[v[1]]]=v[2] }
    s=""; for (i=1; i<=n; ++i) { printf("%s%s", s, value[i]); s="t" };
      printf "n"; delete value }' data.txt >data.new

这会对其进行规范化,以便第一个字段始终包含exon_idgene_id始终位于第四列中,依此类推(第二行上的f值定义字段顺序)。 字段名称不再位于数据中,因为它们已由数据在文件中的位置所隐含。 现在,提取您想要的数据应该是微不足道的。

awk -F 't' '$3 == "pseudogene" { print $4, $5 }' data.new

有时,CSV/TSV 在文件的第一行有列标题,但这对于自动化处理来说很麻烦。 您应该在一个地方一劳永逸地记录字段到列索引的映射。

或者,

如果数据填充比示例建议的要稀疏一些,或者如果您希望不时自由添加或删除某些字段,和/或某些值具有内部结构,则结构化格式可能更适合。 将示例转换为 JSON 非常简单:

awk '{ printf (NR==1 ? "[" : ",n");
    printf "{"; s="";
    for (i=1; i<NF; i +=2) { printf ("%s"%s": %s", s, $i, $(i+1)); s=", " }
    printf "}"; }
  END { printf "]n" }' data.txt >data.json

有诸如YAML和XML之类的替代方案,但是JSON简单,灵活且支持良好(XML在这里似乎非常矫枉过正)。 现在,您可以按属性的名称而不是列号来引用属性:

 jq '.[] | select(.gene_biotype == "pseudogene") |
    { gene_id, gene_name }' data.json

特别是jq工具适用于 JSON 格式(JSON 片段流),因此如果您提交到 JSON 工具链而不是通用 JSON 工具链,则可以进一步简化 Awk 脚本。 这将在一定程度上限制您对工具的选择,但如果您的需求很简单,也许没关系(无论如何,一系列相同结构的 JSON 片段可以很容易地用[..., ..., ...]包装成正确的 JSON 格式)。

awk '{ printf "{"; s="";
    for (i=1; i<NF; i +=2) { printf ("%s"%s": %s", s, $i, $(i+1)); s=", " }
    printf "}"; }' data.txt >data.jsons

然后你可以提取

 jq 'select(.gene_biotype == "pseudogene") |
    { gene_id, gene_name }' data.jsons

如果你想要另一个值为"假基因"的字段,而不是"gene_biotype",请更新你的问题,指出你想在什么条件下提取一个值;或者无条件提取,只需删除select(...)条件,或Awk代码中的$3 == "..."

相关内容

最新更新