根据可能不完整的键合并文件

根据可能不完整的键合并文件

我想合并两个文件,例如如何根据两列的匹配来合并两个文件?但一个文件可能无法包含所有结果。例如

文件1

1 dog
2 cat
3 fox
4 cow

文件2

1 woof
2 meow
4 mooh

想要的输出

1 dog woof
2 cat meow
3 fox
4 cow mooh

答案1

使用 GNU awk 处理数组的数组:

$ awk '{a[$1][(NR>FNR)]=$2} END{for (i in a) print i, a[i][0], a[i][1]}' file{1,2}
1 dog woof
2 cat meow
3 fox
4 cow mooh

或使用任何 awk:

$ awk '{keys[$1]; a[$1,(NR>FNR)]=$2} END{for (i in keys) print i, a[i,0], a[i,1]}' file{1,2}
1 dog woof
2 cat meow
3 fox
4 cow mooh

尽管上面的输出按第一个字段的数字升序排列,但这只是运气/巧合 - 输出行的顺序实际上是由“in”运算符提供的“随机”(通常是哈希顺序)。如果您关心的话,将输出通过管道传输到sort -k1,1n(或PROCINFO["sorted_in"]="@ind_num_asc"在 GNU awk 中的 END 部分的开头设置)。

该解决方案与解决方案之间的显着区别join在于:

  1. 即使输入未排序,而join需要在关键字段上对输入进行排序,这也将起作用,并且,
  2. 如果 file2 中有一行的键不存在于 file1 中(反之亦然),这将以某种方式显示它,以便您可以知道该唯一行来自哪个文件(与添加-a2join命令不同)。

这里有一些更全面的示例输入/输出用于测试:

$ head file{1,2}
==> file1 <==
1 dog
2 cat
4 cow
5 bear

==> file2 <==
1 woof
2 meow
3 growl
4 mooh

然后我们可以运行上面的 awk 脚本来获得相同的输出:

$ awk '{a[$1][(NR>FNR)]=$2} END{for (i in a) print i, a[i][0], a[i][1]}' file{1,2}
1 dog woof
2 cat meow
3  growl
4 cow mooh
5 bear

并注意3 growl前面有一个额外的空白,growl因此您知道这是 file2 中的唯一行,而不是使用join

$ join -a1 -a2 file1 file2
1 dog woof
2 cat meow
3 growl
4 cow mooh
5 bear

您无法区分 file1 中的唯一行(例如5 bear)和 file2 中的唯一行(例如3 growl)。

答案2

假设 file1 和 file2 都已排序,join默认情况下只会连接两个文件都有其密钥的行。因此,在您的情况下,file2 没有键为“3”的行,因此该行未加入。但是,您可以更改此行为。

在以下的手册页中join

   -a FILENUM
          also print unpairable lines from file FILENUM, where FILENUM is 1 or 2, corresponding to FILE1 or FILE2

因此,如果您将该-a1标志添加到join命令中,则 file1 中任何在 file2 中没有匹配键的行也将被打印。

# join -a1 file1 file2
1 dog woof
2 cat meow
3 fox
4 cow mooh

请注意,这不会处理来自 file2 的不可配对的行,因此如果在 file2 中您有另一行类似以下内容:

5 quack

该行不会被打印。您还可以-a2在命令中添加标志join,该标志将打印 file2 中的行,但这只会增加一些混乱,因为您不知道该行是来自 file1 还是来自 file2。

答案3

将您的键和值放入关联数组中并将其打印到 file3 中:

declare -A arr

while read key value
do
    if [ -z ${arr[$key]} ]; then
        arr[$key]=$value
    else
        arr[$key]="${arr[$key]} $value"
    fi
done < <(cat file1 file2)

echo -n > file3

for key in "${!arr[@]}"
do
    echo "$key ${arr[$key]}" >> file3
done

相关内容