【问题标题】:Unix join on multiple fields on two files [closed]Unix加入两个文件的多个字段[关闭]
【发布时间】:2012-10-27 23:01:33
【问题描述】:

我有两个文件

猫 test1.txt

1|2|3|4

2|3|4|4

3|4|5|5

cat test2.txt

1|2|4|5

2|3|5|6

3|5|7|7

我的输出应该是

1|2|3|4|4|5

2|3|4|4|5|6

这就像在字段 1 和 2 上连接两个文件,并从文件 1 中获取 1,2,3,4 的值,从文件 2 中获取 3,4 的值。

请帮我解决这个问题?

【问题讨论】:

  • 如果您可以使用像 sqlite 这样的数据库,这将非常容易 - 这是一个选项吗?

标签: shell unix join scripting awk


【解决方案1】:

尝试在perl 中执行此操作

paste -d '|' file1.txt file2.txt |
    perl -F'\|' -lane '
        print join "|", @F[0..3,6,7] if $F[0] eq $F[4] and $F[1] eq $F[5]
    '

sh

#!/bin/sh

paste -d '|' test1.txt test2.txt | while IFS='|' read a1 a2 a3 a4 a5 a6 a7 a8; do
    if [ $a1 -eq $a5 -a $a2 -eq $a6 ]; then
        echo "$a1|$a2|$a3|$a4|$a7|$a8"
    fi
done

输出

1|2|3|4|4|5
2|3|4|4|5|6

【讨论】:

  • 你的最后一行是错误的,因为两个表中都没有匹配项(应该在每个表的前两个字段上匹配)
  • @DaveRlz : OP 不清楚他对最后一行的期望
  • @sputnick OP很清楚。他们希望在前两个字段上进行连接,这解释了为什么输出中有两行。
  • @sputnick - 他说'就像在字段 1 和 2 上加入两个文件'
  • @sputnick Nice - 我知道我需要改进我的 shell 编程。
【解决方案2】:

嗯,这适用于您的示例:

 sed 's/|/+/' t1.txt>$$.tmp;sed 's/|/+/' t2.txt|join -t \| -j 1 $$.tmp -|sed 's/+/|/';rm $$.tmp

【讨论】:

  • 不需要临时文件,可以使用process substitution:sed ... | join -t \| -j 1 <(sed ...) - | ...
  • 现在我有了一个新的有趣且有用的功能。
【解决方案3】:

这似乎也有效:

$ sed 's/|/\t/2' 1.txt > 1_1.txt; sed 's/|/\t/2' 2.txt > 2_1.txt;
$ join -j1 1_1.txt 2_1.txt | tr ' ' '|'
$ rm 1_1.txt 2_1.txt

无需创建临时文件的单行程序(感谢@dbaupp):

$ join -j1 <(sed 's/|/\t/2' 1.txt) <(sed 's/|/\t/2' 2.txt) | tr ' ' '|'

【讨论】:

  • 不需要临时文件,可以使用process substitution:join -j 1 &lt;(sed ...) &lt;(sed ...) | ...
  • @dbaupp 啊!我为此疯狂地谷歌搜索,但不知道它是怎么称呼的。谢谢!
  • 哈哈,我以前也是这个位置!我知道我想做什么,但我不知道要放入 google 的神奇的“进程替换”字眼!
【解决方案4】:
awk -F\| 'NR == FNR {
  f2[$1, $2] = $3 OFS $4
  next
  }
($1, $2) in f2 {
  print $0, f2[$1, $2]
  }' OFS=\| test2.txt test1.txt

【讨论】:

  • +1 以获得最佳解决方案。我会使用 BEGIN{FS=OFS="|"} 而不是单独分配它们。
  • 感谢 Ed,感谢您在 Usenet 和 stackoverflow 上的所有有用帖子!
  • 这非常有效。谢谢。
【解决方案5】:

另一种解决方案:

awk -F "|" '{getline a < "file1"}NR==1{print a, $3, $4 "\n"}NR==3{print a, $3, $4}' OFS="|" file2

结果:

$ awk -F "|" '{getline a < "file1"}NR==1{print a, $3, $4 "\n"}NR==3{print a, $3, $4}' OFS="|" file2
1|2|3|4|4|5

2|3|4|4|5|6

【讨论】:

    猜你喜欢
    • 2012-12-16
    • 2017-07-09
    • 1970-01-01
    • 2016-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多