在Unix中加入带连字符的索引字段

时间:2012-05-23 16:00:34

标签: unix join merge awk

我是Unix的新手,并且无法根据带有连字符索引的字段加入两个制表符分隔的文本文件。例如:

file1.txt
33-47   10      22      -99     10
33-48   15      22      165     456
33-101  10      22      -99     15.8
33-126  10      22      -99     15.5
34-133  10      22      -99     13
40-109  10      22      -99     12
41-102  88      21      -99     20
45-169  54      214     -99     4
100-11  652     524     87      5
101-25  45      54      153     8
101-26  1285    12      155     9.5

file2.txt
1       5432    545     33-101
1       5524    5420    33-126
0       855520  52220   33-47
0       5463    5420    34-133
0       5563    5423    40-109
1       6098    -99     40-109

本质上,文件1是一个查找表,我想将文件1的匹配行追加到文件2,以便创建一个完整的变量表,即:

file3.txt (expected)
1       5432    545     33-101  10      22      -99     15.8
1       5524    5420    33-126  10      22      -99     15.5
0       855520  52220   33-47   10      22      -99     10
0       5463    5420    34-133  10      22      -99     13
0       5563    5423    40-109  10      22      -99     12
1       6098    -99     40-109  10      22      -99     12

我正在使用Cygwin,并尝试首先按字母顺序排序字段,通常使用LC_COLLATE = C语言环境,以及许多awk NR == FNR命令,但我仍然得到一个空白的outfile。

这是全新的,非常令人沮丧。如果可以的话请帮忙!

谢谢!

2 个答案:

答案 0 :(得分:1)

这对我有用,但我不在Cygwin上:

awk 'NR==FNR{info[$1]=gensub(/[^\t]*\t/,"",1)} NR!=FNR{printf"%s\t%s\n",$0,info[$NF]}' file1.txt file2.txt

我相信有人可以改进......

答案 1 :(得分:1)

我会 非常 对您了解join如何工作感兴趣。

这是一种非常丑陋的方式:

a='{split($f, a, /-/); $f = sprintf("%05d%05d", a[1], a[2]); print}'
join -1 4 -2 1 -o 1.1 1.2 1.3 0 2.2 2.3 2.4 2.5 2.6 2.7 2.8 \
    <(awk -v f=4 "$a" file2.txt | sort -k4,4) | 
    <(awk -v f=1 "$a" file1.txt | sort) \
    awk 'BEGIN {OFS = "\t"} {$4 = substr($4, 1, 5) + 0 "-" substr($4, 6, 5) + 0; print}'

输出:

0       855520  52220   33-47   10      22      -99     10
1       5432    545     33-101  10      22      -99     15.8
1       5524    5420    33-126  10      22      -99     15.5
0       5463    5420    34-133  10      22      -99     13
0       5563    5423    40-109  10      22      -99     12
1       6098    -99     40-109  10      22      -99     12

如果您省略了-o输出规范(并在最终$4中将字段从$1更改为awk),从而缩短命令,这就是输出看起来像(普通字段优先):

33-47   0       855520  52220   10      22      -99     10
33-101  1       5432    545     10      22      -99     15.8
33-126  1       5524    5420    10      22      -99     15.5
34-133  0       5463    5420    10      22      -99     13
40-109  0       5563    5423    10      22      -99     12
40-109  1       6098    -99     10      22      -99     12

上面的工作方法是在键字段中左边填充数字并删除连字符,然后再撤消它。这允许简单的词法排序。

我很想使用sort -V(版本排序)而不是使用填充技术。它给出了正确的排序顺序,但join不同意。