【问题标题】:join columns but print all lines in both files加入列但打印两个文件中的所有行
【发布时间】:2014-03-18 18:52:28
【问题描述】:

假设我有 file1:

2 luke
3 matthew
4 mark
7 john

我有

1 chicken
2 beef
5 lamb
6 fish

我想要以下:

1 [tab]chicken
2 luke[tab]beef
3 matthew[tab]
4 mark[tab]
5 lamb[tab]
6 fish[tab]
7 [tab]john

有点像“加入”,但我也想要其他列。我知道我可以使用 3 个“comm”来完成它并使用 sort 来摆弄它,但是有一个命令可以做到吗?

【问题讨论】:

  • 您的输出不匹配。 id 1 不在file1 中,所以输出显示1 [tab]chicken,但id 7 file1 那么为什么你的输出是7 [tab]john。应该是7 john[tab

标签: bash unix command-line


【解决方案1】:

您只需使用join 的几个选项:

join -a1 -a2 -o 0,1.2,2.2 -e $'\t' tmp1.txt tmp2.txt

-a1-a2 告诉 join 输出文件 1 和文件 2 中无法配对的行(因此包括两个文件中的所有行)。 -o 在输出中指定三列:连接字段 (0)、第一个文件的第二列和第二个文件的第二列。 -e 指定一个字符串来填充空字段(未找到字段)。 $'\t'bash 扩展;传递制表符的一种更兼容的方式是-e $(printf '\t')

【讨论】:

    【解决方案2】:

    您也可以使用 AWK:

    awk 'FNR==NR{a[$1]=$2; i++; next}{ b[$1]=$2; i++} END { OFS="\t"; for (n=1;n<i;++n) print n, a[n], b[n] }' file1 file2
    

    这通过file1(第一个{block})和file2(第二个{block},构建由第一列中的数字索引的数组。然后在最后它打印出每个数组中的所有值。

    【讨论】:

      【解决方案3】:

      这会使用制表符填充空白字段,但字段仍以空格分隔。

      join  -a1 -a2 -o 0,1.2,2.2 -e $'\t' file1 file2
      
      1    chicken
      2 luke beef
      3 matthew   
      4 mark  
      5    lamb
      6    fish
      7 john  
      

      要查看空白字符,请将输出通过管道传输到 | od -c

      要准确获得所需的输出,请使用 awk:

      awk '
          {
              ids[$1]
              if (NR==FNR) 
                  f1[$1]=$2
              else 
                  f2[$1]=$2
          } 
          END {
              n = asorti(ids, sorted_ids)
              for (i=1; i<=n; i++)
                  printf "%d %s\t%s\n", sorted_ids[i], f1[sorted_ids[i]], f2[sorted_ids[i]]
          }
      ' file1 file2
      
      1   chicken
      2 luke  beef
      3 matthew   
      4 mark  
      5   lamb
      6   fish
      7 john  
      

      【讨论】:

      • 很好的解决方案,但是如果您将 \t 更改为 [tab] 您会注意到它不符合 OP 对两个文件中都不存在的填充选项卡的要求。 更新虽然看起来 OP 请求的输出是不正确的,而你拥有的是它应该是的输出。
      • 好眼光。错过了。
      【解决方案4】:

      这个 awk 应该可以工作:

      awk 'FNR==NR{a[$1]=$2;next} $1 in a{print $1, $2, a[$1];delete a[$1];next} {print $1, $2, ""}
           END {for (i in a) print i, a[i]}' OFS='\t' f2 f1|sort -nk1
      1   chicken
      2   luke    beef
      3   matthew
      4   mark
      5   lamb
      6   fish
      7   john
      

      【讨论】:

        【解决方案5】:

        这是awk 的另一种方式。只需将[tab] 替换为\t

        awk '
        NR==FNR { a[$1] = $2 "[tab]"; next }
        ($1 in a) { a[$1] = a[$1] $2; next }
        { a[$1] = "[tab]" $2 }
        END {
            n = asorti(a, s);
            for (x = 1; x <= n; x++)
                print s[x], a[s[x]]}
        ' file1 file2
        1 [tab]chicken
        2 luke[tab]beef
        3 matthew[tab]
        4 mark[tab]
        5 [tab]lamb
        6 [tab]fish
        7 john[tab]
        

        【讨论】:

          猜你喜欢
          • 2017-04-16
          • 1970-01-01
          • 2019-08-20
          • 2016-01-16
          • 2018-06-11
          • 1970-01-01
          • 1970-01-01
          • 2019-01-14
          • 1970-01-01
          相关资源
          最近更新 更多