nev*_*int 13 unix linux bash join
我该怎么做?
File1看起来像这样:
foo 1 scaf 3
bar 2 scaf 3.3
Run Code Online (Sandbox Code Playgroud)
File2看起来像这样:
foo 1 scaf 4.5
foo 1 boo 2.3
bar 2 scaf 1.00
Run Code Online (Sandbox Code Playgroud)
我想要做的是找到 在字段1,2和3相同时在File1和File2中共同出现的行.
有办法吗?
the*_*edk 14
这是正确的答案(在使用标准GNU coreutils工具方面,而不是在perl/awk中编写自定义脚本).
$ join -j1 -o1.2,1.3,1.4,1.5,2.5 <(<file1 awk '{print $1"-"$2"-"$3" "$0}' | sort -k1,1) <(<file2 awk '{print $1"-"$2"-"$3" "$0}' | sort -k1,1)
bar 2 scaf 3.3 1.00
foo 1 scaf 3 4.5
Run Code Online (Sandbox Code Playgroud)
好的,它是如何工作的:
首先,我们将使用一个join可以合并两条线的好工具.join有两个要求:
我们需要在输入文件中生成密钥,为此我们使用一个简单的awk脚本:
$ cat file1
foo 1 scaf 3
bar 2 scaf 3.3
$ <file1 awk '{print $1"-"$2"-"$3" "$0}'
foo-1-scaf foo 1 scaf 3
bar-2-scaf bar 2 scaf 3.3
Run Code Online (Sandbox Code Playgroud)
你看,我们在第一列添加了一些像" foo-1-scaf " 这样的关键字.我们对file2做同样的事情.BTW.<file awk,只是花哨的写作方式awk file,或cat file | awk.
我们还应该按键对文件进行排序,在我们的例子中这是第1列,所以我们添加到命令的末尾| sort -k1,1(从第1列到第1列的文本排序)
此时我们可以生成文件file1.with.key和file2.with.key并加入它们,但假设这些文件很大,我们不想将它们复制到文件系统上.相反,我们可以使用一个称为bash 进程替换的东西来生成命名管道的输出(这将避免任何不必要的中间文件创建).有关详细信息,请阅读提供的链接.
我们的目标语法是: join <( some command ) <(some other command)
最后一件事是解释花哨的连接参数: -j1 -o1.2,1.3,1.4,1.5,2.5
-j1 - 按第1列中的键加入(在两个文件中)-o - 仅输出那些字段1.2(第1.3一个文件字段2),(第一个文件列3)等.
这样我们就加入了行,但join只输出必要的列.
从这篇文章中吸取的教训应该是:
Jon*_*ler 11
大量的实验加上对手册页的仔细审查表明你不能直接加入多个列 - 而且我所有的加入实例都很有趣,只使用一个连接列.
因此,任何解决方案都需要以某种方式将要连接的列连接成一列.标准连接命令还要求其输入处于正确的排序顺序 - 在GNU连接(info coreutils join)中有一个关于它并不总是需要排序数据的注释:
但是,作为GNU扩展,如果输入没有不可修改的行,则排序顺序可以是任何将两个字段视为相等的顺序,当且仅当上述排序比较认为它们相等时.
使用给定文件执行此操作的一种可能方法是:
awk '{printf("%s:%s:%s %s %s %s %s\n", $1, $2, $3, $1, $2, $3, $4);}' file1 |
sort > sort1
awk '{printf("%s:%s:%s %s %s %s %s\n", $1, $2, $3, $1, $2, $3, $4);}' file2 |
sort > sort2
join -1 1 -2 1 -o 1.2,1.3,1.4,1.5,2.5 sort1 sort2
Run Code Online (Sandbox Code Playgroud)
这将在开始时创建一个复合排序字段,使用":"分隔子字段,然后对文件进行排序 - 对于两个文件中的每一个.然后,join命令将连接两个复合字段,但仅打印出非复合(非连接)字段.
输出是:
bar 2 scaf 3.3 1.00
foo 1 scaf 3 4.5
Run Code Online (Sandbox Code Playgroud)
join -1 1 -2 1 -1 2 -2 2 -1 3 -2 3 -o 1.1,1.2,1.3,1.4,2.4 file1 file2
在MacOS X 10.6.3上,这给出了:
$ cat file1
foo 1 scaf 3
bar 2 scaf 3.3
$ cat file2
foo 1 scaf 4.5
foo 1 boo 2.3
bar 2 scaf 1.00
$ join -1 1 -2 1 -1 2 -2 2 -1 3 -2 3 -o 1.1,1.2,1.3,1.4,2.4 file1 file2
foo 1 scaf 3 4.5
bar 2 scaf 3.3 4.5
$
Run Code Online (Sandbox Code Playgroud)
这是加入第3场(仅限) - 这不是想要的.
您需要确保输入文件的排序顺序正确.
将前三个字段与awk结合起来可能是最简单的:
awk '{print $1 "_" $2 "_" $3 " " $4}' filename
Run Code Online (Sandbox Code Playgroud)
然后,您可以join在“字段1”上正常使用
你可以试试这个
awk '{
o1=$1;o2=$2;o3=$3
$1=$2=$3="";gsub(" +","")
_[o1 FS o2 FS o3]=_[o1 FS o2 FS o3] FS $0
}
END{ for(i in _) print i,_[i] }' file1 file2
Run Code Online (Sandbox Code Playgroud)
输出
$ ./shell.sh
foo 1 scaf 3 4.5
bar 2 scaf 3.3 1.00
foo 1 boo 2.3
Run Code Online (Sandbox Code Playgroud)
如果你想省略不常见的行
awk 'FNR==NR{
s=""
for(i=4;i<=NF;i++){ s=s FS $i }
_[$1$2$3] = s
next
}
{
printf $1 FS $2 FS $3 FS
for(o=4;o<NF;o++){
printf $i" "
}
printf $NF FS _[$1$2$3]"\n"
} ' file2 file1
Run Code Online (Sandbox Code Playgroud)
输出
$ ./shell.sh
foo 1 scaf 3 4.5
bar 2 scaf 3.3 1.00
Run Code Online (Sandbox Code Playgroud)