![根据同一字段中的排序值合并两个排序文件](https://linux22.com/image/99903/%E6%A0%B9%E6%8D%AE%E5%90%8C%E4%B8%80%E5%AD%97%E6%AE%B5%E4%B8%AD%E7%9A%84%E6%8E%92%E5%BA%8F%E5%80%BC%E5%90%88%E5%B9%B6%E4%B8%A4%E4%B8%AA%E6%8E%92%E5%BA%8F%E6%96%87%E4%BB%B6.png)
我想合并两个排序文件中的行,不一定具有相同的长度,但具有相同的数据字段和相同的标题,从基于特定列的顺序的维护标题之后开始。例如,文件1为:
header 1
header 2
header 3
cat 4 aa
dog 5 ab
ostrich 10 cd
fish 13 cc
文件2是:
header 1
header 2
header 3
lemur 3 dd
alligator 4 ca
lemming 16 ad
我想 1) 保留相同的标题,但 2) 根据第 2 列对以下行进行排序。我想要的输出是:
header 1
header 2
header 3
lemur 3 dd
cat 4 aa
alligator 4 ca
dog 5 ab
ostrich 10 cd
fish 13 cc
lemming 16 ad
我已经查看过,但无法使用awk
or找到针对这种情况的解决方案join
。
答案1
awk
和join
是错误的工具。
sed '/^$/q' file1; sort -snmk2,2 <(sed '1,/^$/d' file1) <(sed '1,/^$/d' file2)
答案2
使用现代(版本> 4.0)的 GNU awk,你可以这样做
awk '
FNR>4 {a[$0]=$2; next};
NR==FNR;
END {
PROCINFO["sorted_in"] = "@val_num_asc";
for (i in a) print i;
}
' file1 file2
解释:
FNR>4 {a[$0]=$2; next};
创建非标题行的排序字段的数组NR==FNR;
仅对第一个文件评估 TRUE,并且仅对 达到FNR>4
,导致为第一个文件打印标题行PROCINFO["sorted_in"] = "@val_num_asc"
按值对数组进行排序(即存储字段 $2)for (i in a) print i
打印指数排序数组的(存储的非标题行)
测试
$ awk 'FNR>4 {a[$0]=$2; next}; NR==FNR; END {PROCINFO["sorted_in"] = "@val_num_asc"; for (i in a) print i;}' file1 file2
header 1
header 2
header 3
lemur 3 dd
cat 4 aa
alligator 4 ca
dog 5 ab
ostrich 10 cd
fish 13 cc
lemming 16 ad
答案3
使用具有进程替换的 shell ( ksh93
, bash
, ...) (参见结尾以了解无进程替换的替代方案):
cat <( head -n 3 file1 ) \
<( sort -k2,2n <( tail -n +4 file1 | tr -s ' ' '\t' ) \
<( tail -n +4 file2 | tr -s ' ' '\t' ) | uniq )
这将导致:
header 1
header 2
header 3
lemur 3 dd
alligator 4 ca
cat 4 aa
dog 5 ab
ostrich 10 cd
fish 13 cc
lemming 16 ad
该命令将标题行file1
与排序操作的结果连接起来。排序是在某些输入的第二个字段上以数字方式完成的,并且任何重复的行(鳄鱼、狐猴和旅鼠)都会从uniq
结果中删除。
file1
sort 的输入将是和的无标题内容file2
,传递tr
以用单个制表符替换连续空格(示例数据中的列之间的空格数量不均匀)。
结果以制表符分隔。
使用相同工具的等效方法:
cat <( head -n 3 file1 ) \
<( sort -k2,2n <( cat <( tail -n +4 file1 ) \
<( tail -n +4 file2 ) | tr -s ' ' '\t' ) | uniq )
没有cat
s 和进程替换:
{ head -n 3 file1;
{ tail -n +4 file1; tail -n +4 file2; } | tr -s ' ' '\t' | sort -k2,2n | uniq; }