28

我需要在两个字段上加入两个文件。但是,即使连接失败,我也应该检索文件 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||
4

3 回答 3

31

它是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
于 2012-11-14T16:23:38.170 回答
10

要准确地完成问题的要求比以前的答案要复杂一些,并且需要这样的东西:

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

文件 1.tmp

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

文件 2.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加入字段
    • 1.2file1.tmp 的字段 2,即冒号右边的所有内容
    • 2.2file2.tmp 的字段 2
  • tr ':' '|'最后,我们将冒号转换回管道以进行最终输出。

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

01|a|jack|d|nemesis|f
02|b|ron|c|brave|d
03|d|tom|e||
于 2016-10-14T17:41:50.407 回答
-1

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

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

这是一种特殊情况,它可能不适用或无法与此处发布的上述技术相提并论,但如果它对正在寻找左外连接的人有用(即仅适用于不匹配的情况),则将其放在那里。搜索“^.*2”将为您提供匹配的案例。如果您有一个多字段文件(更常见的情况),但您只关心单个连接字段,您可以使用 Awk 创建一个仅键文件(为每个文件),然后按上述处理。

于 2019-10-08T15:19:11.780 回答