如何使用awk进行连接

如何使用awk进行连接,awk,Awk,这是我的输入文件 Identifier Relation A 1 A 2 A 3 B 2 B 3 C 1 C 2 C 3 我想根据“关系”字段将此文件连接到自身。 示例输出文件 A 1 C 1 A 2 B 2 A 2 C 2 B 2 C 2 A 3 B 3 A 3 C 3 B 3 C 3 我使用了以下awk脚本: awk'NR==FN

这是我的输入文件

Identifier Relation
A           1
A           2
A           3
B           2
B           3
C           1
C           2
C           3
我想根据“关系”字段将此文件连接到自身。 示例输出文件

A 1 C 1
A 2 B 2
A 2 C 2
B 2 C 2
A 3 B 3
A 3 C 3
B 3 C 3
我使用了以下awk脚本:
awk'NR==FNR{a[NR]=$0;next}{for(a中的k)如果(a[k]~$2)打印a[k],$0}'输入>输出

然而,我不得不做另一个awk步骤来删除与自身连接的行,即a1;b2b2等

该文件的第二个问题是它打印连接的两个方向,因此 与C1 A1一起打印在另一行上。 这两行显示相同的关系,我不想包括这一行。我只想看到其中一行,即“A1 C1”或“C1 A1”,而不是两者。
非常感谢您的任何建议/指导。

肯定有一个仅使用awk的解决方案,但我将提出一个使用awk和排序的解决方案,因为我认为它非常简单,不需要将整个文件内容存储在awk变量中。其思路如下:

  • 重写输入文件,使“关系”字段位于第一位(
    a1
    ->
    1a
  • 使用
    排序-n
    将具有相同“关系”的所有行放在一起
  • 使用awk组合具有相同“关系”的连续行
这将转化为:

awk '{print $2 " " $1}' input | sort -n | 
  awk '{if ($1==lastsel)printf " "; else if(lastsel) printf "\n"; lastsel=$1; printf "%s %s", $2, $1;}END{if(lastsel)printf"\n"}'
A 1 C 1
A 2 B 2 C 2
A 3 B 3 C 3

编辑:如果每行只需要一个i-j关系:

awk '{print $2 " " $1}' input | sort -n |
  awk '$1!=rel{rel=$1;item=$2;next;} {printf "%s %s %s %s\n", item, rel, $2, $1;}'
A 1 C 1
A 2 B 2
A 2 C 2
A 3 B 3
A 3 C 3
请注意此解决方案的以下限制:

awk 'NR>1{ar[$2]=(ar[$2]$1);}\
    END{ for(key in ar){\
        for(i=1; i<length(ar[key]); i++) {\
            for(j=i+1; j<length(ar[key])+1; j++) {\
                print substr(ar[key],i,1), key, substr(ar[key],j,1), key;\
            }\
        }\
    }}' infile
  • 如果给定的n只有一个条目,则不会输出任何内容(没有输出,例如
    d1
  • 所有关系在第一列中都始终有按字典顺序排列的第一项(例如
    a1c1
    ,但决不
    b1c1

    • 以下是一个仅适用于awk的解决方案:

      awk 'NR>1{ar[$2]=(ar[$2]$1);}\
          END{ for(key in ar){\
              for(i=1; i<length(ar[key]); i++) {\
                  for(j=i+1; j<length(ar[key])+1; j++) {\
                      print substr(ar[key],i,1), key, substr(ar[key],j,1), key;\
                  }\
              }\
          }}' infile
      
      注:

      • 如果一个数字只出现一次,则不会为该数字生成输出
      • 输出的顺序取决于输入的顺序。(没有字母排序!!)。也就是说,如果第二个输入行是
        c1
        ,那么
        array[1]=“CAB”
        ,第一个输出行将是
        c1a1
      • 由于
        NR>1

      使用awk并支持连接和排序的替代解决方案

      $ join -j 2 <(sort -k2 -k1,1 file){,} 
      | awk '$2!=$3 && !($3 FS $2 in a){a[$2 FS $3]; print$2,$1,$3,$1}'
      A 1 C 1
      A 2 B 2
      A 2 C 2
      B 2 C 2
      A 3 B 3
      A 3 C 3
      B 3 C 3
      

      $join-j2非常感谢@secolive的回复!!!然而,我希望我的输出如下:a1c1;a2b2;a2c2;b2c2;因此,每个组合在不同的行上,而不是附加在一行中。