组织数据

时间:2013-11-28 09:49:27

标签: python perl bash sed

我的数据文件如下所示:

chr1 762440 762981 SAMD11 
chr1 858932 859148 KLHL17 SAMD11 NOC2L 
chr1 859786 860145 KLHL17 SAMD11 NOC2L
chr1 890663 891747 KLHL17 NOC2L  SAMD11  HES4 

我希望将所有名称排在另一个之下,并使用前三列中的值。

像这样的东西

chr1 762440 762981 SAMD11 
chr1 858932 859148 KLHL17
chr1 858932 859148 SAMD11 
chr1 858932 859148 NOC2L 
chr1 859786 860145 KLHL17 
chr1 859786 860145 SAMD11 
chr1 859786 860145 NOC2L

此输出用于前三行,但是整个集合都需要。

每行中的名称数量不固定,请记住这一点(可以是1或5或10或20个名称)

What I thought

使用sed -i .bak将名称一个放在另一个下面以及前三列中的值。

但最终它变得过于复杂。

你能想到一个更简单的解决方法吗?

谢谢

8 个答案:

答案 0 :(得分:5)

使用awk

awk '{for (i=4;i<=NF;i++) print $1,$2,$3,$i}' file
chr1 762440 762981 SAMD11
chr1 858932 859148 KLHL17
chr1 858932 859148 SAMD11
chr1 858932 859148 NOC2L
chr1 859786 860145 KLHL17
chr1 859786 860145 SAMD11
chr1 859786 860145 NOC2L
chr1 890663 891747 KLHL17
chr1 890663 891747 NOC2L
chr1 890663 891747 SAMD11
chr1 890663 891747 HES4

答案 1 :(得分:3)

以下是我在Perl中的表现:

#!/usr/bin/perl

use strict;
use warnings;
use 5.010;

while (<DATA>) {
  chomp;
  my @line = split;
  for my $field (@line[3 .. $#line]) {
    say "@line[0 .. 2] $field";
  }
}

__END__
chr1 762440 762981 SAMD11 
chr1 858932 859148 KLHL17 SAMD11 NOC2L 
chr1 859786 860145 KLHL17 SAMD11 NOC2L
chr1 890663 891747 KLHL17 NOC2L  SAMD11  HES4 

答案 2 :(得分:2)

在bash中(100%内部命令) 我有这个答案:

#!/bin/bash


while read ONE TWO THREE FOUR
do
    for ARG in $FOUR
    do
        if [ ${ARG:0:1} != "(" ]    #<-- filtering out args with parentheses
        then
            echo "$ONE $TWO $THREE $ARG"
        fi
    done
done <"/path/to/your/datafile"

但是既然你改变了问题,这也会改变答案:

#!/bin/bash


while read ONE TWO THREE FOUR
do
    for ARG in $FOUR
    do
        echo "$ONE $TWO $THREE $ARG"
    done
done <"/path/to/your/datafile"

答案 3 :(得分:2)

怎么样:

while(<DATA>) {
    chomp;
    my @data = split" ",$_;
    my $prefix = join" ",@data[0..2];
    for(3 .. $#data) {
        next if $data[$_] =~ /\([-+]?\d+\)/;
        say $prefix, " ", $data[$_];
    }
}

__DATA__
chr1 762440 762981 SAMD11 (-98410)
chr1 858932 859148 KLHL17 (-36927), SAMD11 (-2081), NOC2L (+35639)
chr1 859786 860145 KLHL17 (-36001), SAMD11 (-1155), NOC2L (+34713)

<强>输出:

chr1 762440 762981 SAMD11
chr1 858932 859148 KLHL17
chr1 858932 859148 SAMD11
chr1 858932 859148 NOC2L
chr1 859786 860145 KLHL17
chr1 859786 860145 SAMD11
chr1 859786 860145 NOC2L

答案 4 :(得分:2)

因为你也有Python标签,所以我在Python中这样做(从命令行的stdin或文件读取输入,并将输出写入stdout)。

#!/usr/bin/python

import fileinput

for line in fileinput.input():
    parts = line.strip().split()
    first_three = " ".join(parts[:3])

    for code in parts[3:]:
        print("{first_three} {code}".format(first_three=first_three, code=code))

答案 5 :(得分:2)

sed 's/^/\
/
t b
: b
s/\(\n\)\(\([^[:blank:][:cntrl:]]\{1,\}[[:blank:]]\{1,\}\)\{3\}\)\([^[:blank:][:cntrl:]]\{1,\}\)[[:blank:]]\{1,\}\([^[:blank:][:cntrl:]][^[:cntrl:]]*\)[[:blank:]]*$/\1\2\4\1\2\5/
t b
s/^\n//' YourFile

处理每一行,扩展任何最后一个参数。可以删除第一个t b,但它会通过安全性重置测试

答案 6 :(得分:1)

这可能适合你(GNU sed):

sed -r 's/^((\S+\s+){3})(\S+)\s+(\S+)/\1\3\n\1\4/;P;D' file

答案 7 :(得分:0)

#!/usr/bin/perl
use warnings;
use strict; 

请阅读您的文件:

my $infile = 'in.txt';
open my $input, '<', $infile or die "Can't open to $infile: $!";

拆分空格中的每一行(尽管如果您的数据以制表符分隔,我建议使用split(/\t/);

while (<$input>){
    my @split = split(/\s+/);
    print "$split[0]\t$split[1]\t$split[2]\t$split[3]\n";
}

输出:

chr1    762440  762981  SAMD11
chr1    858932  859148  KLHL17
chr1    859786  860145  KLHL17
chr1    890663  891747  KLHL17
chr1    896072  896354  NOC2L
chr1    954920  955343  HES4
chr1    1195296 1195488 PUSL1
chr1    1243975 1244505 UBE2J2
chr1    1284370 1284709 ACAP3
chr1    1373711 1374872 CCNL2