我有一个选项卡消除了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_id
,gene_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 == "..."
。