我有一张这样的表:
symbol refseq seqname start stop strand
Susd4 NM_144796 chr1 184695027 184826500 +
Ptpn14 NM_008976 chr1 191552147 191700574 +
Cd34 NM_001111059 chr1 196765080 196787475 +
Gm5698 NM_001166637 chr1 31034088 31055753 -
Epha4 NM_007936 chr1 77363760 77511663 -
Sp110 NM_175397 chr1 87473474 87495392 -
Gbx2 chr1 91824537 91827751 -
Kif1a chr1 94914855 94998430 -
Bcl2 NM_009741 chr1 108434770 108610879 -
我想用以下条件提取数据:
1)“refseq”列中的值不缺少的行
2)对于“start
”和“stop
”列中的值,只为每行保留一个值:如果“strand
”列中的值为“ +
“,取”start
“中的值;如果“strand
”列中的值为“-
”,请取“stop
”中的值。
这就是预料之中:
Susd4 NM_144796 chr1 184695027 +
Ptpn14 NM_008976 chr1 191552147 +
Cd34 NM_001111059 chr1 196765080 +
Gm5698 NM_001166637 chr1 31055753 -
Epha4 NM_007936 chr1 77511663 -
Sp110 NM_175397 chr1 87495392 -
Bcl2 NM_009741 chr1 108610879 -
答案 0 :(得分:2)
我很想让输入分隔符保持不变,因此空格和制表符分隔字段,而不是仅仅坚持选项卡。这意味着您需要在第一个(跳过标题行)后面有六个字段的记录:
awk 'NR > 1 && NF == 6 { if ($6 == "+") x = $4; else x = $5; print $1, $2, $3, x; }'
如果您想更多地控制输出格式,可以使用OFS进行调整,或使用printf
:
awk 'BEGIN { OFS = "\t" }
NR > 1 && NF == 6 { if ($6 == "+") x = $4; else x = $5; print $1, $2, $3, x; }'
awk 'NR > 1 && NF == 6 { if ($6 == "+") x = $4; else x = $5;
printf "%-8s %-12s %s %9s\n", $1, $2, $3, x; }'
还有其他方法可以处理它,我敢肯定......
第一个脚本产生:
Susd4 NM_144796 chr1 184695027
Ptpn14 NM_008976 chr1 191552147
Cd34 NM_001111059 chr1 196765080
Gm5698 NM_001166637 chr1 31055753
Epha4 NM_007936 chr1 77511663
Sp110 NM_175397 chr1 87495392
Bcl2 NM_009741 chr1 108610879
我相信内容是正确的;可以通过多种方式改进格式。最后一个脚本产生:
Susd4 NM_144796 chr1 184695027
Ptpn14 NM_008976 chr1 191552147
Cd34 NM_001111059 chr1 196765080
Gm5698 NM_001166637 chr1 31055753
Epha4 NM_007936 chr1 77511663
Sp110 NM_175397 chr1 87495392
Bcl2 NM_009741 chr1 108610879
您可以根据需要调整字段宽度。
答案 1 :(得分:2)
这可能适合你(GNU sed):
sed -r '1d;/(\S+\s+){5}\S+/!d;/\+$/s/\S+\s+//5;/-$/s/\S+\s+//4' file
编辑:
1d
删除标题行/(\S+\s+){5}\S+/!d;
如果该行没有6个字段,则将其删除/\+$/s/\S+\s+//5
如果该行以+
结尾,则删除第5个字段/-$/s/\S+\s+//4
如果该行以-
结尾,则删除第4个字段答案 2 :(得分:0)
awk -F'\t' 'NR>1&&$2{print $NF=="+"?$4:$5}' file
输出:
184695027
191552147
196765080
31055753
77511663
87495392
108610879
如果您还想要输出中的其他值:
awk 'BEGIN{FS=OFS="\t"}NR>1&&NF==6{print $1,$2,$3,$NF=="+"?$4:$5}' file
输出:
Susd4 NM_144796 chr1 184695027
Ptpn14 NM_008976 chr1 191552147
Cd34 NM_001111059 chr1 196765080
Gm5698 NM_001166637 chr1 31055753
Epha4 NM_007936 chr1 77511663
Sp110 NM_175397 chr1 87495392
Bcl2 NM_009741 chr1 108610879
编辑,将格式调整为OP的输出示例:
awk 'BEGIN{FS=OFS="\t"}NR>1&&NF==6{$4=$NF=="+"?$4:" ";$5=$NF=="+"?" ":$5;print}' file
输出:
Susd4 NM_144796 chr1 184695027 +
Ptpn14 NM_008976 chr1 191552147 +
Cd34 NM_001111059 chr1 196765080 +
Gm5698 NM_001166637 chr1 31055753 -
Epha4 NM_007936 chr1 77511663 -
Sp110 NM_175397 chr1 87495392 -
Bcl2 NM_009741 chr1 108610879 -
答案 3 :(得分:0)
当您处理包含字段的文本文件时,awk
通常优于sed
,因为awk
旨在帮助解析带字段的文本文件。
表格中的列如何设置?它们是以制表符分隔的,还是使用空格来帮助排列列?
如果这是制表符分隔表,您可以使用awk
检查第二个字段是否为空:
awk '
{
if ($2 == "") {
print "Missing 'refseqence' in symbol " $1
}
' $myfile
如果您的文件使用空格来对齐各个字段,您仍然可以使用其内置的substr`函数来使用awk
。
awk '
{
if (substr($0, 9, 12) ~ /^ *$/)
print "Missing 'refsequence' in symbol " substr ($0, 1, 7)
}
}
' $myfile
顺便说一下,我在这里相当罗嗦,向您展示使其易于理解的语法。我可以使用一些快捷方式将它们放在一行:
awk '$2 == "" {print "Missing refseqence in symbol " $1}' $myfile
awk 'substr($0, 9, 12) ~ /^ */ {print "Missing refsequnece in symbol " substr($0, 1, 7) }' $myfile