如何使用条件表达式来选择数据?

时间:2013-01-11 19:04:43

标签: awk sed

我有一张这样的表:

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   -

4 个答案:

答案 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