【问题标题】:Append two columns adding a specific integer at each value in Unix附加两列,在 Unix 中的每个值处添加一个特定的整数
【发布时间】:2015-09-25 10:23:17
【问题描述】:

我有两个这样的文件:

# 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 会变得一团糟。

【问题讨论】:

    标签: unix awk sed cat


    【解决方案1】:
    # 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]/ { $1 += StartIndex; LastIndex = $1;print }
       ' YourFiles*
    
    • 结果取决于文件顺序
    • 输出分隔符由 OFS 值设置(此处选项卡)

    【讨论】:

    • 像魅力一样工作,非常感谢。对我来说,awk 语法理解起来很复杂,如果你有时间并且会指出一些解释或参考,我可以在哪里找到它们
    • 直接在源代码中添加了一些注释。网上有很多关于 (g)awk 的 pdf、html 或其他书籍,有助于更深入地了解
    【解决方案2】:

    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 中的最后一个数字。它还在 $before 中保留前导空格的长度加上 $max 以格式化所有未来的数字以占用相同的空间(使用printf)。

    您没有显示距离列是如何对齐的,即

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

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

    【讨论】:

    • 非常感谢,但我不是 Perl 专家。我应该如何启动脚本?只是在输入文件不起作用后放置输入文件
    • @user2710445:我将文件名硬编码为file1file2。如果您希望它们作为脚本的参数,只需将它们替换为shift。如open my $F1, '&lt;', shift or die $!
    猜你喜欢
    • 2021-08-17
    • 1970-01-01
    • 1970-01-01
    • 2019-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-30
    相关资源
    最近更新 更多