使用另一个文件重命名文件中的名称而不使用循环

时间:2012-07-02 08:06:02

标签: perl matlab sed awk grep

我有两个文件:

(one.txt)看起来像这样:

>ENST001 

(((....)))

(((...)))

>ENST002 

(((((((.......))))))

((((...)))

我还有10000多个ENST

(two.txt)看起来像这样:

>ENST001   110

>ENST002  59

以及其他所有ENST

等等

我基本上想通过(two.txt)中两个字段的组合替换(one.txt)中的ENST,所以结果将如下所示:

>ENST001_110 

(((....)))

(((...)))

>ENST002_59 

(((((((.......))))))

((((...)))

我写了一个matlab脚本来做到这一点,但是因为它为(two.txt)中的所有行循环,所以需要花费6个小时才能完成,所以我认为使用awk,sed,grep甚至perl我们都可以得到结果在几分钟内。这就是我在matlab中所做的:

frf = fopen('one.txt', 'r');       
frp = fopen('two.txt', 'r');                                     
fw = fopen('result.txt', 'w');    

while feof(frf) == 0

line = fgetl(frf);
first_char = line(1);

if strcmp(first_char, '>') == 1 % if the line in one.txt start by > it is the ID 

   id_fold = strrep(line, '>', ''); % Reomve the > symbol


   frewind(frp)     % Rewind two.txt file after each loop

    while feof(frp) == 0

        raw = fgetl(frp);
        scan = textscan(raw, '%s%s');
        id_pos = scan{1}{1};
        pos = scan{2}{1};

            if strcmp(id_fold, id_pos) == 1  % if both ids are the same


                id_new = ['>', id_fold, '_', pos];

                fprintf(fw, '%s\n', id_new);

            end    

    end    

else

    fprintf(fw, '%s\n', line);  % if the line doesn't start by > print it to results



end  

结束

6 个答案:

答案 0 :(得分:4)

使用awk的一种方法。 FNR == NR处理参数中的第一个文件并保存每个数字。第二个条件处理第二个文件,当第一个字段与数组中的键匹配时,修改附加该数字的该行。

awk '
    FNR == NR { 
        data[ $1 ] = $2; 
        next 
    } 
    FNR < NR && data[ $1 ] { 
        $0 = $1 "_" data[ $1 ] 
    } 
    { print }
' two.txt one.txt

输出:

>ENST001_110

(((....)))

(((...)))

>ENST002_59

(((((((.......))))))

((((...)))

答案 1 :(得分:3)

使用sed,您最初只能在two.txt上运行,您可以根据需要制作sed个命令,并在one.txt运行:

第一种方式

sed "$(sed -n '/>ENST/{s=.*\(ENST[0-9]\+\)\s\+\([0-9]\+\).*=s/\1/\1_\2/;=;p}' two.txt)" one.txt

第二种方式

如果文件太大,您将获得too many arguments error以前的方式。因此,还有另一种方法可以解决此错误。您需要逐个执行所有三个命令:

sed -n '1i#!/bin/sed -f
/>ENST/{s=.*\(ENST[0-9]\+\)\s\+\([0-9]\+\).*=s/\1/\1_\2/;=;p}' two.txt > script.sed
chmod +x script.sed
./script.sed one.txt

第一个命令将形成sed脚本,可以根据需要修改one.txt。 chmod将使此新脚本可执行。最后一个命令将执行命令。所以每个文件只读一次。没有任何循环。 请注意,第一个命令由两行组成,但仍然是一个命令。如果你要删除换行符,它将破坏脚本。这是因为i中的sed命令。您可以在“sed手册页”中查找详细信息。

答案 2 :(得分:2)

此Perl解决方案将修改后的one.txt文件发送到STDOUT

use strict;
use warnings;

open my $f2, '<', 'two.txt' or die $!;

my %ids;

while (<$f2>) {
  $ids{$1} = "$1_$2" if /^>(\S+)\s+(\d+)/;
}

open my $f1, '<', 'one.txt' or die $!;

while (<$f1>) {
  s/^>(\S+)\s*$/>$ids{$1}/;
  print;
}

答案 3 :(得分:1)

解决问题。在perl我会做这样的事情:

#!/usr/bin/perl

open(FH1, "one.txt");
open(FH2, "two.txt");
open(RESULT, ">result.txt");

my %data;

while (my $line = <FH2>)
{
    chomp(line);

    # Delete leading angle bracket
    $line =~ s/>//d;

    # split enst and pos
    my ($enst, $post) = split(/\s+/, line);

    # Store POS with ENST as key
    $data{$enst} = $pos;
}

close(FH2);

while (my $line = <FH1>)
{
    # Check line for ENST
    if ($line =~ m/^>(ENST\d+)/)
    {
        my $enst = $1;

            # Get pos for ENST
        my $pos = $data{$enst};

            # make new line
        $line = '>' . $enst . '_' . $pos . '\n';
    }

    print RESULT $line;
}

close(FH1);
close(RESULT);

答案 4 :(得分:1)

这可能适合你(GNU sed):

sed -n '/^$/!s|^\(\S*\)\s*\(\S*\).*|s/^\1.*/\1_\2/|p' two.txt | sed -f - one.txt

答案 5 :(得分:1)

试试这个MATLAB解决方案(无循环):

%# read files as cell array of lines
fid = fopen('one.txt','rt');
C = textscan(fid, '%s', 'Delimiter','\n');
C1 = C{1};
fclose(fid);
fid = fopen('two.txt','rt');
C = textscan(fid, '%s', 'Delimiter','\n');
C2 = C{1};
fclose(fid);

%# use regexp to extract ENST numbers from both files
num = regexp(C1, '>ENST(\d+)', 'tokens', 'once');
idx1 = find(~cellfun(@isempty, num));       %# location of >ENST line
val1 = str2double([num{:}]);                %# ENST numbers
num = regexp(C2, '>ENST(\d+)', 'tokens', 'once');
idx2 = find(~cellfun(@isempty, num));
val2 = str2double([num{:}]);

%# construct new header lines from file2
C2(idx2) = regexprep(C2(idx2), ' +','_');

%# replace headers lines in file1 with the new headers
[tf,loc] = ismember(val2,val1);
C1( idx1(loc(tf)) ) = C2( idx2(tf) );

%# write result
fid = fopen('three.txt','wt');
fprintf(fid, '%s\n',C1{:});
fclose(fid);