更改大文件的列的字符

时间:2014-03-14 16:57:53

标签: string shell sed awk

我必须用另一个文件的相应列替换大文件的每个(备用)行的单个第n个字符。例如,我每隔5个字符就会改变一次。

文件1:

 >chr1:101842566-101842576
  CCTCAACTCA
 >chr1:101937281-101937291
 GAATTGGATA
 >chr1:101964276-101964286
 AAAAAATAGG
 >chr1:101972950-101972960
 ggctctcatg
 >chr1:101999969-101999979
 CATCATGACG

file2的:

 G
 A
 T
 A
 C

输出:

 >chr1:101842566-101842576
 CCTCGACTCA
 >chr1:101937281-101937291
 GAATAGGATA
 >chr1:101964276-101964286
 AAAATATAGG
 >chr1:101972950-101972960
 ggctAtcatg
 >chr1:101999969-101999979
 CATCCTGACG

每个(备用)行中的字符数可能很大。行数也很大。如何有效地完成这项工作?

4 个答案:

答案 0 :(得分:4)

以下是awk的一种方式:

awk 'NR==FNR{a[NR]=$1;next}!/^>/{$1=substr($1,1,n-1) a[++i] substr($1,n+1)}1' n=5 f2 f1

<强>解释

  • 我们迭代第二个文件并将其存储在以行号索引的数组中。
  • 将第二个文件加载到内存后,我们将移至第二个文件。
  • 我们会查找不以>开头的行。
  • 找到后,我们替换数组中的值。我们使用substr函数执行此操作。
  • 定义的变量n允许您修改第n个字符
  • 对于没有>的行,我们使用1打印它们,默认为 印刷。
  • 此解决方案假定文件的格式如上所示。也就是说,第一个文件将始终以>开头,后跟您要更改的行。第二个文件的替换将按照看到的顺序进行。

<强>演示:

每五个字符:

$ awk 'NR==FNR{a[NR]=$1;next}!/^>/{$1=substr($1,1,n-1) a[++i] substr($1,n+1)}1' n=5 f2 f1
>chr1:101842566-101842576
CCTCGACTCA
>chr1:101937281-101937291
GAATAGGATA
>chr1:101964276-101964286
AAAATATAGG
>chr1:101972950-101972960
ggctAtcatg
>chr1:101999969-101999979
CATCCTGACG

每个第3个角色:

$ awk 'NR==FNR{a[NR]=$1;next}!/^>/{$1=substr($1,1,n-1) a[++i] substr($1,n+1)}1' n=3 f2 f1
>chr1:101842566-101842576
CCGCAACTCA
>chr1:101937281-101937291
GAATTGGATA
>chr1:101964276-101964286
AATAAATAGG
>chr1:101972950-101972960
ggAtctcatg
>chr1:101999969-101999979
CACCATGACG

答案 1 :(得分:3)

这就是我使用perl的方法。首先将所有file2读入一个数组,然后遍历该数组,从file1读取两行和两行,打印未修改的第一行,然后更改第二行的第5个字符:

#!/usr/bin/perl
use strict;
use warnings;
use diagnostics;
#use Data::Printer;

# Read all of file2

my $lines;

open(FILE, $ARGV[1]);
{
    local $/;
    $lines = <FILE>;
}
close(FILE);

my @new_chars = split(/\n/, $lines);

# Read and process file1

open(FILE, $ARGV[0]);

foreach my $new_char (@new_chars) {
    # >chr1:101842566-101842576
    my $line = <FILE>;
    print $line;
    #  CCTCAACTCA
    $line = <FILE>;
    $line =~ s/^(....)./$1$new_char/; # Replace 5th character
    print $line;
}

close(FILE);

答案 2 :(得分:1)

您可以使用Python中的mmap替换文件中的列:

#!/usr/bin/env python3
"""Replace inplace a column of a large file.

Usage:
    $ ./replace-inplace file1 file2 5
"""
import sys
from mmap import ACCESS_WRITE, mmap

def main():
    ncolumn = int(sys.argv[3]) - 1 # 1st column is 1
    with open(sys.argv[1], 'r+b') as file1:
        with mmap(file1.fileno(), 0, access=ACCESS_WRITE) as mm:
            with open(sys.argv[2], 'rb') as file2:
                while True:
                    mm.readline()   # ignore every other line
                    pos = mm.tell() # remember current position
                    if not mm.readline(): # EOF
                        break
                    replacement = file2.readline().strip()[0]
                    mm[pos + ncolumn] = replacement # replace the column

main()

它假定您用字节替换一个字节,即文件中没有移动内容。

答案 3 :(得分:1)

这可能适合你(GNU sed,paste和cat):

cat file1 | paste -d\\n\\t\\n - file2 - | sed -r 's/^(.)\t(.{4})./\2\1/' >file3

将file2中的数据嵌入到file1中,然后重新排列。