重新编号列并替换文件中的行

时间:2015-04-28 21:48:13

标签: bash perl

我有一个如下文件。对于1ABC线,我想将1.line替换为3.line,将2.line替换为1.line,将3.line替换为4.line,将4.line替换为2.line。我想为2ABC线做同样的事情(在实际文件中我有1ABC,2ABC,3ABC ...... 1000ABC线)。更换线后,我应重新编号3.column。我该怎么做(我必须保留输出文件中列之间的间距)?

输入文件:

1ABC     C1    1   0.349  
1ABC     H2    2   0.123   
1ABC     O1    3   0.217  
1ABC     H4    4   0.180  
2ABC     C1    5   2.015 
2ABC     H2    6   0.573     
2ABC     O1    7   1.929    
2ABC     H4    8   1.867  

请求的输出:

1ABC     H2    1   0.123   
1ABC     H4    2   0.180 
1ABC     C1    3   0.349   
1ABC     O1    4   0.217
2ABC     H2    5   0.573    
2ABC     H4    6   1.867  
2ABC     C1    7   2.015  
2ABC     O1    8   1.929 

2 个答案:

答案 0 :(得分:1)

您已将其标记为perl,我还没有看到perl答案,所以我的方法就是这样:

看起来就像您正在做的是基于第二列的固定订单。那是对的吗?具体为H2,H4,C1,O1。

按第一列排序,然后排序,然后将第三列排序为 - 基本上 - 行号 - 您得到:

use strict;
use warnings;
my %results;

while (<DATA>) {
    my ( $code, $OH, $index, $value ) = split;
    $results{$code}{$OH} = $value;
}

my $rank         = 1;
my @output_order = qw ( H2 H4 C1 O1 );

foreach my $code ( sort keys %results ) {
    foreach my $OH (@output_order) {
        print join( "\t", $code, $OH, $rank++, $results{$code}{$OH} ), "\n";
    }
}

__DATA__ 
1ABC     C1    1   0.349  
1ABC     H2    2   0.123   
1ABC     O1    3   0.217  
1ABC     H4    4   0.180  
2ABC     C1    5   2.015 
2ABC     H2    6   0.573     
2ABC     O1    7   1.929    
2ABC     H4    8   1.867  

将打印:

1ABC    H2  1   0.123
1ABC    H4  2   0.180
1ABC    C1  3   0.349
1ABC    O1  4   0.217
2ABC    H2  5   0.573
2ABC    H4  6   1.867
2ABC    C1  7   2.015
2ABC    O1  8   1.929

答案 1 :(得分:0)

最直接的方法是只读取四行,然后按修改顺序将它们打印出来。

n=1

while read -r a1 b1 c1 d1 &&
      read -r a2 b2 c2 d2 &&
      read -r a3 b3 c3 d3 &&
      read -r a4 b4 c4 d4
do
    printf '%-8s %-5s %-3s %s\n' "$a2" "$b2" "$((n++))" "$d2"
    printf '%-8s %-5s %-3s %s\n' "$a4" "$b4" "$((n++))" "$d4"
    printf '%-8s %-5s %-3s %s\n' "$a1" "$b1" "$((n++))" "$d1"
    printf '%-8s %-5s %-3s %s\n' "$a3" "$b3" "$((n++))" "$d3"
done

这会带来过多的重复性,通常是代码味道。更优雅的方法是将重新排序和重新编号分成不同的阶段。

reorder() {    
    while read -r l1 && read -r l2 && read -r l3 && read -r l4; do
        printf '%s\n' "$l2" "$l4" "$l1" "$l3"
    done
}

renumber() {
    awk '{ $3 = ++n; print }'
}

reorder < in.txt | renumber > out.txt

请注意,这不会保留列之间的间距。