将数据粘贴在bash中

时间:2017-06-14 11:50:28

标签: python bash shell awk sed

我向您展示了我需要对数据做些什么的示例。我有两个用标签分隔的文本文件。

cat in1.tsv

111 A B C
111 D E F
111 G H I
222 A B C
333 A B C
333 D E F

此表可以有大约数千行。列数小于100.第一列可以有重复的值(如111和333)。

cat in2.tsv

111 a b c 
222 a b c 
333 d e f

在此文件中,仅在第1列中显示一次值。我需要根据第一列匹配合并这两个文件。

cat output.tsv

111 A B C 111 a b c
111 D E F 111 a b c
111 G H I 111 a b c
222 A B C 222 a b c 
333 A B C 333 d e f
333 D E F 333 d e f 

如果矩阵的大小相同,我的解决方案是有效的:

paste  <(sort in1.tsv) <(sort in2.tsv) > output.tsv

我很感激awk,bash或其他程序的任何帮助,这些程序可以快速运行很多行。

5 个答案:

答案 0 :(得分:3)

Awk救援!

awk 'BEGIN{FS=OFS="\t"}FNR==NR{for(i=2;i<=NF;i++) map[$1]=(map[$1] FS $i); next}$1 in map{print $0,$1,map[$1]}' in2.tsv in1.tsv

按照预期以制表符分隔格式生成输出。如果您不希望o / p标签分离,请删除OFS="\t"

就逻辑而言,创建一个地图,其中包含in2.csv上每列1的值到哈希地图map[],然后在in1.csv上选择包含$1的行与形成的地图相同并打印行内容。

答案 1 :(得分:2)

以下是bash方法:

首先让我们对每个文件进行排序:

LC_ALL=C sort init1.tsv -S75% -t$'\t' -k1,1 > init1.tsv.sorted

LC_ALL=C sort init2.tsv -S75% -t$'\t' -k1,1 > init2.tsv.sorted

然后,而不是pastingjoin在第一列,

join init1.tsv.sorted init2.tsv.sorted -1 1 -2 2 -t$'\t'

如果您需要特定类型的连接,这似乎是左外连接,那么我会这样做:

join init1.tsv.sorted init2.tsv.sorted -1 1 -2 2 -t$'\t' -a1

快速说明,-S指定您想要使用多少RAM,您希望此操作的速度越快,您应该使用的越多。

答案 2 :(得分:2)

join命令似乎几乎可以满足您的需求:

$ join in1.tsv in2.tsv
111 A B C a b c
111 D E F a b c
111 G H I a b c
222 A B C a b c
333 A B C d e f
333 D E F d e f

默认行为是基于第一列连接行,空格为分隔符。使用格式选项-o可以得到相同的结果。 Dmitry Polonskiy在评论中说:

,也需要排序
join -o 1.1,1.2,1.3,1.4,2.1,2.2,2.3,2.4 <(sort in1.tsv) <(sort in2.tsv)

答案 3 :(得分:2)

在Python中,不依赖于正在排序的文件:

#!/usr/bin/env python

with open("in1.tsv") as in1, open("in2.tsv") as in2:
    d = {line.split()[0]: line for line in in2}
    for line in in1:
        print(line.strip(), d[line.split()[0]], sep="\t", end="")

这基本上创建了从第一列的值到in2.tsv的行的映射,然后在in1.tsv的行上循环,并使用映射将它们与in2.tsv的相应行组合

答案 4 :(得分:2)

这可能适合你(GNU sed):

 sed -r 's#^(\S+)\s.*#/^\1/s/$/ &/#' file2 | sed -f - file

从第二个文件创建一个sed脚本。此脚本包含一个正则表达式,匹配时将第二个文件中的匹配记录附加到第一个匹配的记录中。