【问题标题】:Two file numeric comparison in awkawk中的两个文件数字比较
【发布时间】:2013-10-26 11:21:59
【问题描述】:

我正在尝试比较两个文件的内容,这两个文件都只是一列数字,即

文件1:

1.2
2.6
3.4
4.7
5.3

文件2:

5.1
4.8
3.2
2.5
1.6

输出应该只是 file1 中大于 file2 中相应行的行数;所以在这种情况下它只是

3

【问题讨论】:

    标签: linux awk


    【解决方案1】:

    这是一个仅使用 AWK 的解决方案,每次只从每个输入文件中读取一行。

    BEGIN {
        if (ARGC != 3)
        {
            print "Usage: this_program <file1> <file2>"
            exit(1)
        }
    
        c = 0
        for (;;)
        {
            result = getline < ARGV[1]
            if (1 != result)
                break
            n1 = $1 + 0
    
            result = getline < ARGV[2]
            if (1 != result)
                break
            n2 = $1 + 0
            if (n1 > n2)
                ++c;
        }
        print c
    }
    

    附:我是 Python 的粉丝,为了好玩,我也用 Python 解决了这个问题。

    import sys
    
    if sys.version_info.major < 3:
        import itertools
        zip = itertools.izip
    
    with open(sys.argv[1]) as f1, open(sys.argv[2]) as f2:
        print(sum(float(x) > float(y) for x, y in zip(f1, f2)))
    

    注意事项:

    • zip() 对从两个来源读取的值进行配对。 zip(f1, f2) 对从两个输入文件中的每一个读取的行进行配对。

    • 当您在 Python 2.x 上运行它时,我使用了 itertools.izip(),因此它一次只能处理一行。 Python 2 中内置的zip() 一次读取所有数据并构建一个列表。

    • 错误检查并不明显,但确实存在。如果输入不能用作float 值,您将得到异常;如果用户没有指定至少两个输入文件,你会得到一个异常。

    • 这使用了一个稍微低俗的技巧:sum() 会将布尔值 True 视为 1,将布尔值 False 视为 0。因此,这将获取所有行的计数&gt; 比较为真。

    【讨论】:

      【解决方案2】:

      awk 单个进程可以完成这项工作:

      awk 'NR==FNR{a[NR]=$0;next}a[FNR]>$0{i++}END{print i}' file1 file2
      

      输出:

      3
      

      编辑

      通过阅读 JonathanLeffler 和 steveha 的 cmets,我将添加另一个解决方案,以避免将怪物文件保存到内存中。仍然是单个 awk 进程:

       awk '{getline x < "file2"}$0>x{i++}END{print i}' file1
      

      输出:

      3
      

      【讨论】:

      • 这会将所有file1 读入内存。对于某些输入,这可能不切实际。
      • @steveha 我同意你的看法。但我在 OP 的问题中没有看到任何通知/描述,说他正面临怪物文件。在实践中,这种衬里(数组中的一个文件,检查另一个文件)相对经常使用。总有办法用单个 awk 来处理这类问题。我会更新答案,并行读取两个文件
      • 非常感谢您的帮助;我完全忘记了从长远来看文件大小可能是一个问题,但就目前而言,我正在使用的文件只有兆字节的数量级。
      【解决方案3】:

      尝试使用paste,后跟awk

      paste file1 file2 | awk '$1>$2 {i++} END {print i}'
      

      输出:

      3
      

      【讨论】:

      • 这是对所描述问题的明显解决方案的干净实现。此外,它的优点是如果文件大小为千兆字节,它不会将整个文件 1 存储在 (awk's) 内存中,因此它可以在需要时处理庞大的文件。缺点是通过管道移动所有数据的成本。
      • @JonathanLeffler 感谢您的评论和解释!
      • 我建议将0 添加到$1$2 中,以强制它们转换为数字;否则,您可能会在某些输入上得到令人惊讶的结果。我刚刚测试过,只要输入以数字形式工作,AWK 似乎确实做了正确的事情,但表达式 100.3 &lt; "abc" 在我测试时评估为 true。
      • @steveha 感谢您的反馈。我同意。但我希望它保持简单,除非 OP 要求。他只在他的档案中提到了数字
      猜你喜欢
      • 2014-12-25
      • 2022-11-12
      • 2018-03-04
      • 1970-01-01
      • 2012-09-05
      • 2012-05-17
      • 1970-01-01
      • 2017-01-31
      相关资源
      最近更新 更多