追加两列,在 Unix 中的每个值处添加一个特定的整数

Append two columns adding a specific integer at each value in Unix

我有两个这样的文件:

# step         distance            
           0    4.48595407961296e+01
        2500    4.50383737781376e+01
        5000    4.53506757198727e+01
        7500    4.51682465277482e+01
       10000    4.53410353656445e+01

  # step   distance             
           0    4.58854106214881e+01
        2500    4.58639266431320e+01
        5000    4.60620560167519e+01
        7500    4.58990075106227e+01
       10000    4.59371359946124e+01

所以我想将两个文件连接在一起,同时保持间距。 特别是,第二个文件需要记住第一个文件的结束值并从第一个文件开始计数。

输出:

  # step         distance            
               0    4.48595407961296e+01
            2500    4.50383737781376e+01
            5000    4.53506757198727e+01
            7500    4.51682465277482e+01
           10000    4.53410353656445e+01
           12500    4.58854106214881e+01
           15000    4.58639266431320e+01
           17500    4.60620560167519e+01
           20000    4.58990075106227e+01
           22500    4.59371359946124e+01

使用 calc 很容易解决的问题是间距需要正确才能工作,在这种情况下 calc 会变得一团糟。

Perl 来拯救!

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

open my $F1, '<', 'file1' or die $!;
my ($before, $after, $diff);
my $max = 0;
while (<$F1>) {
    print;
    my ($space1, $num, $space2) = /^(\s*) ([0-9]+) (\s*)/x or next;

    ($before, $after) = ($space1, $space2);
    $diff = $num - $max;
    $max = $num;
}

$before = length "$before$max";  # We'll need it to format the computed numbers.

open my $F2, '<', 'file2' or die $!;
<$F2>; # Skip the header.
while (<$F2>) {
    my ($step, $distance) = split;
    $step += $max + $diff;
    printf "% ${before}d%s%s\n", $step, $after, $distance;
}

程序会记住 $max 中的最后一个数字。它还保留前导 whitespace 加上 $before 中的 $max 的长度,以格式化所有未来数字以占用相同的 space(使用 printf)。

您没有说明距离列是如何对齐的,即

       20000    4.58990075106227e+01
       22500   11.59371359946124e+01 # dot aligned?
       22500    11.34572478912301e+01 # left aligned?

程序会以后一种方式对齐它。如果您想要前者,请使用与步骤列类似的技巧。

# start awk and set the *Step* between file to 2500
awk -v 'Step=2500' '

   # 1st line of 1 file (NR count every line, from each file) init and print header
   NR == 1 {LastFile = FILENAME; OFS = "\t"; print}

   # when file change (new filename compare to previous line read)
   #  Set a new index (for incremental absolute step from relative one) and new filename reference
   FILENAME != LastFile { StartIndex = LastIndex + Step; LastFile = FILENAME}

   # after first line and for every line stating witha digit (+ space if any)
   #  calculate absolute step and replace relative one, print the new content
   NR > 1 && /^[[:blank:]]*[0-9]/ {  += StartIndex; LastIndex = ;print }
   ' YourFiles*
  • 结果取决于文件顺序
  • 输出分隔符由 OFS 值设置(此处为制表符)