Shell 通过追加记录合并两个文本文件(更新现有记录,插入新记录)
我正在寻找一个UNIX shell解决方案来执行两个文本文件之间的SQLShell 通过追加记录合并两个文本文件(更新现有记录,插入新记录),shell,unix,awk,merge,uniq,Shell,Unix,Awk,Merge,Uniq,我正在寻找一个UNIX shell解决方案来执行两个文本文件之间的SQLMERGE(或UPSERT)等效操作,其中一些字段是关键字段,其他字段可以更新/覆盖 输入数据 这是我的原始数据: AA;123;2016-01-31;1;456.53 AA;123;2016-02-01;1;75.24 AB;123;2000-08-08;1;756.1 AB;456;2016-07-07;2;8.24 CC;123;2007-07-21;15;10.34 CC;456;2009-09-09;9;943.6
MERGE
(或UPSERT
)等效操作,其中一些字段是关键字段,其他字段可以更新/覆盖
输入数据
这是我的原始数据:
AA;123;2016-01-31;1;456.53
AA;123;2016-02-01;1;75.24
AB;123;2000-08-08;1;756.1
AB;456;2016-07-07;2;8.24
CC;123;2007-07-21;15;10.34
CC;456;2009-09-09;9;943.65
CC;789;2005-04-23;1;1345.6
其中前三个字段(产品、客户和日期)是关键字段,后两个字段(数量和金额)可以更新
这是我的第二个文件,仅包含新的和更新的数据:
AA;123;2016-01-31;7;983.63
AA;123;2016-08-24;17;1687.73
CC;456;2009-09-09;11;2161.65
DD;91;2016-08-03;5;98.48
这两个文件已按以下顺序排序:
sort -t';' -k1 -k2 -k3
第一条和第三条记录应覆盖现有行(更新数量和金额),而第二条和第三条记录应作为新行插入
所需输出
AA;123;2016-01-31;7;983.63
AA;123;2016-08-24;17;1687.73
AA;123;2016-02-01;1;75.24
AB;123;2000-08-08;1;756.1
AB;456;2016-07-07;2;8.24
CC;123;2007-07-21;15;10.34
CC;456;2009-09-09;11;2161.65
CC;789;2005-04-23;1;1345.6
DD;91;2016-08-03;5;98.48
我正在寻找一些使用sort
、uniq
或awk
和perl
的快速解决方案
$ awk -F\; '{a[$1 FS $2 FS $3]= $4 FS $5} END {PROCINFO["sorted_in"]="@ind_str_asc"; for (i in a) print i FS a[i]}' file1 file2
AA;123;2016-01-31;7;983.63
AA;123;2016-02-01;1;75.24
AA;123;2016-08-24;17;1687.73
AB;123;2000-08-08;1;756.1
AB;456;2016-07-07;2;8.24
CC;123;2007-07-21;15;10.34
CC;456;2009-09-09;11;2161.65
CC;789;2005-04-23;1;1345.6
DD;91;2016-08-03;5;98.48
解释:
{
a[$1 FS $2 FS $3] = $4 FS $5 # write records overwriting where needed
}
END {
PROCINFO["sorted_in"]="@ind_str_asc" # for sort order
for (i in a) # output indexed records
print i FS a[i]
}
解释:
{
a[$1 FS $2 FS $3] = $4 FS $5 # write records overwriting where needed
}
END {
PROCINFO["sorted_in"]="@ind_str_asc" # for sort order
for (i in a) # output indexed records
print i FS a[i]
}
当第1、第2、第3个字段的索引与文件2中的索引匹配时,您希望覆盖文件1中的行。也就是说,file2比file1具有“首选项”,因此,如果file1中的一行在file2中没有对应关系,则只打印该行 如果是这样,那么从file2开始打印所有两个文件,并跳过file1-file2-file3-wise中重复的那些行怎么样?然后,通过管道对排序后的输出进行排序:
$ awk -F";" '!seen[$1, $2, $3]++' f2 f1 | sort
AA;123;2016-01-31;7;983.63
AA;123;2016-02-01;1;75.24
AA;123;2016-08-24;17;1687.73
AB;123;2000-08-08;1;756.1
AB;456;2016-07-07;2;8.24
CC;123;2007-07-21;15;10.34
CC;456;2009-09-09;11;2161.65
CC;789;2005-04-23;1;1345.6
DD;91;2016-08-03;5;98.48
当第1、第2、第3个字段的索引与文件2中的索引匹配时,您希望覆盖文件1中的行。也就是说,file2比file1具有“首选项”,因此,如果file1中的一行在file2中没有对应关系,则只打印该行 如果是这样,那么从file2开始打印所有两个文件,并跳过file1-file2-file3-wise中重复的那些行怎么样?然后,通过管道对排序后的输出进行排序:
$ awk -F";" '!seen[$1, $2, $3]++' f2 f1 | sort
AA;123;2016-01-31;7;983.63
AA;123;2016-02-01;1;75.24
AA;123;2016-08-24;17;1687.73
AB;123;2000-08-08;1;756.1
AB;456;2016-07-07;2;8.24
CC;123;2007-07-21;15;10.34
CC;456;2009-09-09;11;2161.65
CC;789;2005-04-23;1;1345.6
DD;91;2016-08-03;5;98.48
我正要说有太多的FS。。。你刚把它取下来。好的!我们都有相同的输出,我也喜欢你提供了一个很好的解释,做得好!是的,我在我的
测试.awk
和命令行中修复了它,但是忘记了发布的版本。。。TGIF.NR==FNR和其他块是相同的,所以不需要两个单独的块。只要去掉NR==FNR{…}
块,剩下的东西对这两个文件都很好。我真的需要在发布之前开始校对这些。我正要说有一个FS太多了。。。你刚把它取下来。好的!我们都有相同的输出,我也喜欢你提供了一个很好的解释,做得好!是的,我在我的测试.awk
和命令行中修复了它,但是忘记了发布的版本。。。TGIF.NR==FNR和其他块是相同的,所以不需要两个单独的块。只要去掉NR==FNR{…}
块,剩下的东西对这两个文件都很好。我真的需要在发布之前开始校对这些内容。然后我在发布这个问题后找到了两分钟。然后我在发布这个问题后找到了两分钟。@EdMorton一般来说,我们什么时候应该避免使用逗号来创建索引?当我们有像123
这样的行时,它也可以是123
?总是使用FS
来防止它不是很安全吗?12 3
vs1 23
问题发生在您的下标之间没有放置任何内容,因此它们都连接到123
。使用、
或FS
解决了这个问题。当您要打印数组索引和/或您有多个引用索引的位置时(例如,{key=$1fs$2}seen[key]+{map[key]=$NF;..}END{for(map中的i)print i,map[i]}
),您应该使用,否则您应该使用,
,以便简洁。@EdMorton非常有帮助,一如既往@EdMorton一般来说,我们什么时候应该避免使用逗号来创建索引?当我们有像123
这样的行时,它也可以是123
?总是使用FS
来防止它不是很安全吗?12 3
vs1 23
问题发生在您的下标之间没有放置任何内容,因此它们都连接到123
。使用、
或FS
解决了这个问题。当您要打印数组索引和/或您有多个引用索引的位置时(例如,{key=$1fs$2}seen[key]+{map[key]=$NF;..}END{for(map中的i)print i,map[i]}
),您应该使用,否则您应该使用,
,以便简洁。@EdMorton非常有帮助,一如既往!