Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/unix/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Shell 通过追加记录合并两个文本文件(更新现有记录,插入新记录)_Shell_Unix_Awk_Merge_Uniq - Fatal编程技术网

Shell 通过追加记录合并两个文本文件(更新现有记录,插入新记录)

Shell 通过追加记录合并两个文本文件(更新现有记录,插入新记录),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

我正在寻找一个UNIX shell解决方案来执行两个文本文件之间的SQL
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
vs
1 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
vs
1 23
问题发生在您的下标之间没有放置任何内容,因此它们都连接到
123
。使用
FS
解决了这个问题。当您要打印数组索引和/或您有多个引用索引的位置时(例如,
{key=$1fs$2}seen[key]+{map[key]=$NF;..}END{for(map中的i)print i,map[i]}
),您应该使用
,否则您应该使用
,以便简洁。@EdMorton非常有帮助,一如既往!