我有一个制表符分隔的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来填充空白字段以对齐和提取我想要的列,但我认为将其用于未来的用法是很好的。
提前谢谢!
答案 0 :(得分:1)
这就是awk的制作方式:
awk '$1 == "gene_biotype" {print $4, $6}' < input.txt
说明:$ N表示一个字段,默认情况下用空格分隔。任何空白。等式检查说“仅当第一个字段与gene_biotype匹配时才执行剩余的行”。然后打印相应的字段。如果你想删除引用,你可以查看gsub
函数,或者你可能超级懒惰并将输出传递给sed
。
答案 1 :(得分:0)
也许更好的问题是,“我如何正确地规范化这些数据”。您的标记字段格式不适合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格式(stream of 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”且值为“pseudogene”,请更新您的问题以指明您要在何种条件下提取值;或者无条件地提取,只需删除select(...)
条件或Awk代码中的$3 == "..."
。