在unix中的两个文件上左外连接

时间:2012-11-14 16:09:23

标签: unix join

我需要在两个字段上加入两个文件。但是我应该检索文件1中的所有值,即使连接失败就像左外连接一样。

文件1:

01|a|jack|d
02|b|ron|c
03|d|tom|e

文件2:

01|a|nemesis|f
02|b|brave|d
04|d|gorr|h

输出:

01|a|jack|d|nemesis|f
02|b|ron|c|brave|d
03|d|tom|e||

3 个答案:

答案 0 :(得分:27)

这是join -t '|' file1 file2 -a1

使用的选项:

t :分隔符。
a :决定必须打印不成对行的文件编号。

join -t '|' file1 file2 -a2会执行右外连接

示例运行

   [aman@aman test]$ cat f1  
    01|a|jack|d

    02|b|ron|c

    03|d|tom|e
    [aman@aman test]$ cat f2
    01|a|nemesis|f

    02|b|brave|d

    04|d|gorr|h
    [aman@aman test]$ join -t '|'  f1 f2 -a1
    01|a|jack|d|a|nemesis|f

    02|b|ron|c|b|brave|d

    03|d|tom|e

答案 1 :(得分:8)

要完全解决问题要求比以前的答案复杂一点,并且需要这样的事情:

sed 's/|/:/2' file1 | sort -t: >file1.tmp
sed 's/|/:/2' file2 | sort -t: >file2.tmp
join -t':' file1.tmp file2.tmp -a1 -e'|' -o'0,1.2,2.2' | tr ':' '|'

Unix连接只能加入单个字段AFAIK,因此您必须使用使用不同分隔符的文件来" 连接两个字段上的两个文件",在这种情况下前两个领域。我会使用冒号,但如果存在于您需要使用其他内容的任何输入中,例如标签字符可能会更好生产用途的选择。我还在新的复合字段sort -t:上重新排序输出,对于示例输入文件没有区别,但是对于真实世界数据。 sed 's/|/:/2'将第二次出现的管道替换为文件中每行的冒号。

file1.tmp

01|a:jack|d
02|b:ron|c
03|d:tom|e

file2.tmp

01|a:nemesis|f
02|b:brave|d
04|d:gorr|h

现在我们使用join过滤的tr输出以及一些更高级的选项:

  • -t':'指定临时冒号分隔符
  • -a1左外连接
  • -e'|'指定失败连接的替换字符串,基本上是最终输出分隔符N-1次,其中N是连接到file2.tmp中冒号右侧的管道分隔字段的数量。在这种情况下,N = 2,因此一个管道字符。
  • -o'0,1.2,2.2'指定输出格式:
    • 0加入字段
    • file1.tmp的
    • 1.2字段2,即冒号的所有内容
    • 2.2 file2.tmp
    • 的字段2
  • tr ':' '|'最后,我们将冒号转换回管道以进行最终输出。

输出现在与前一个答案没有完全匹配的问题样本输出匹配:

01|a|jack|d|nemesis|f
02|b|ron|c|brave|d
03|d|tom|e||

答案 2 :(得分:0)

最近我遇到了一个非常简单的输入文件(只有一个字段)的问题,因此没有考虑分隔符。

cat file1 > k1
cat file2 >> k1
sort k1 | uniq -c | grep "^.*1 "  
will give you lines that occur in only 1 file

这是一个特例,它可能不适用或无法与此处发布的上述技术相提并论,但会在此处发布,以防它对正在寻找左外部连接的人有用(即,仅适用于不匹配的情况)。摸索“ ^。* 2”将为您提供匹配的大小写。如果您有一个多字段文件(更常见的情况),但是您只关心单个连接字段,则可以使用Awk创建仅密钥文件(针对每个文件),然后按上述步骤进行处理。