【问题标题】:Compare first column of one file with the first column of second and print associated column of each if there was a match将一个文件的第一列与第二个文件的第一列进行比较,如果匹配,则打印每个文件的关联列
【发布时间】:2018-11-14 14:40:34
【问题描述】:

我有两个文件,我需要比较它们的第一列,如果找到匹配项,我想从两个文件中输出相应的值。

与此 Q 类似,但我想打印两个文件中的列而不是一个:How to compare multiple columns in two files and retrieve the corresponding value from another column if match found

文件1.txt

adeqY   33.7
AIsLX   65.6
AmuBv   1589.0
aZMIx   84.4

文件2.txt

AmuBv foo
iwwlp bar
adeqY hi
qUbJZ bye

输出

hi 33.7
foo 1589.0

我有以下awk 命令,但我只设法从 File2 打印第二列匹配:

awk 'FNR==NR{a[$1]; next} ($1) in a {print $2 a[$2]}' File1.txt File2.txt

a[$2] 不想打印

提前致谢。

【问题讨论】:

    标签: bash awk sysadmin


    【解决方案1】:

    请您尝试关注一下。

    awk 'FNR==NR{a[$1]=$2;next} ($1 in a){print $2,a[$1]}' Input_file1  Input_file2
    

    输出如下。

    foo 1589.0
    hi 33.7
    

    你的尝试中的问题:你在FNR==NR条件下做得很好,你的a[$1]没有任何价值,它只在数组@中创建了它的索引987654325@ 这就是为什么它在读取第二个 Input_file 时无法打印任何内容的原因。

    【讨论】:

      【解决方案2】:

      您尝试做的实际上是在存储在文本文件中的两个表上进行 INNER JOIN,而 Linux join 命令就是为此而设计的。

      试试:

      join -t' ' -1 1 -2 1 -o 2.2,1.2 <(sort file1.txt) <(sort file2.txt) 
      foo 1589.0
      hi 33.7
      

      解释:

      • 字段分隔符指定为-t。我假设您的数据在这些文本文件中由一个空格分隔。
      • -1 1 -2 1 表示连接左侧文件的第一个字段和右侧文件的第一个字段。
      • -o 2.2,1.2 定义了您要返回的字段。第二个文件的第二个字段,然后是第一个文件的第二个字段。
      • 最后,请注意,我对输入文件进行了排序,因为文件需要按您打算加入的字段进行排序,以便 Linux 加入工作。

      另请参阅此博客 (ref)。

      【讨论】:

        【解决方案3】:

        这里发生的情况是,一旦您在最后一个 awk 语句中打印结果,a[] 数组就不再在范围内,因此第二个值没有打印出来。

        也许有另一种方法可以做到这一点awk,但这是我想出的解决方案:

        for each in $(comm -1 -2 <(awk '{print $1 }' file1.txt | sort ) <(awk '{print $1 }' file2.txt | sort) ); do echo $(grep $each file2.txt | awk '{print $2}') $(grep $each file1.txt | awk '{print $2}') ; done;
        

        这个输出:

        foo 1589.0
        hi 33.7
        

        解释:

        • 对这两个文件运行comm 命令。
        • comm 的两个“文件”实际上是进程替换的,因此它们首先被排序(comm 需要排序的输入)并且只显示第一列。
        • comm-1 -2 参数告诉它只打印文件中的公共元素(它可以显示第一个文件独有的元素、第二个文件独有的元素或两者共有的元素)
        • 从两个文件中获得共同元素后,for each 这些共同元素,继续并使用 awk 对每个文件中出现的行进行 grep,并仅显示第二个值。

        所以,最后,我们需要一个 bash for 循环、sortcommawk 多次。可能不是最优雅的解决方案,但它可以完成工作。

        【讨论】:

          【解决方案4】:

          尝试 Perl 变体

          $ cat eskp1.txt
          adeqY   33.7
          AIsLX   65.6
          AmuBv   1589.0
          aZMIx   84.4
          
          $ cat eskp2.txt
          AmuBv foo
          iwwlp bar
          adeqY hi
          qUbJZ bye
          
          $ perl -F"\s+" -lane 'BEGIN { %kv=map{split /\s+/ } qx(cat eskp1.txt) } { print "$F[1] $kv{$F[0]}" if $kv{$F[0]} } ' eskp2.txt
          foo 1589.0
          hi 33.7
          

          【讨论】:

            猜你喜欢
            • 2019-12-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-08-20
            • 2021-10-16
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多