我想在 file2 的基础上更新 file1 。如果file2中的任何行是新的,那么它应该添加到file1中。如果file2中的任何行已经在file1中,那么如果file2中的时间更长,则用file2中的行更新该行。
文件1
DL,1111111100,201312051013,val,FIX01,OptIn,N,Ext1,Ext2
DL,1111111101,201312051014,val,FIX01,OptIn,Y,Ext1,Ext2
DL,1111111102,201312051015,val,FIX01,OptIn,Y,Ext1,Ext2
DL,1111111103,201312051016,val,FIX01,OptIn,N,Ext1,Ext2
file2的
DL,1111111101,201312041013,val,FIX02,OptIn,N,Ext1,Ext2
DL,1111111102,201312051016,val,FIX02,OptIn,N,Ext1,Ext2
DL,1111111102,201312051017,val,FIX02,OptIn,N,Ext1,Ext2
DL,1111111104,201312051014,val,FIX01,OptIn,Y,Ext1,Ext2
DL,1111111104,201312051016,val,FIX02,OptIn,Y,Ext1,Ext2
newfile1
DL,1111111100,201312051013,val,FIX01,OptIn,N,Ext1,Ext2
DL,1111111101,201312051014,val,FIX01,OptIn,Y,Ext1,Ext2
DL,1111111102,201312051017,val,FIX02,OptIn,N,Ext1,Ext2
DL,1111111103,201312051016,val,FIX01,OptIn,N,Ext1,Ext2
DL,1111111104,201312051016,val,FIX02,OptIn,Y,Ext1,Ext2
注意:
file2
中的最新第二字段值“1111111104”是基于日期列(第3字段)的较新(201312051016)然后旧值(201312051014)。 file1
中的条目已经与file2
中的新日期“201312041013”相比具有最新日期“201312051014”。 / LI>
我对此没有太多尝试,因为作为初学者,它确实具有复杂的条件..
BEGIN { FS = OFS = "," }
FNR == NR {
m=$2;
a[m] = $0;
next
}
{
if($2 in a)
{
split(a[$2],datetime,",")
if($3>datetime[3])
print $0;
else
print a[$2]"Old time"
}
else print $0"NOMATCH";
delete a[$2];
}
答案 0 :(得分:3)
假设您可以按如下方式启动awk
:
awk -f script.awk input2.csv input1.csv > result.csv
您可以使用以下脚本获取所需的输出:
BEGIN {
FS = OFS = ","
}
FILENAME == "input2.csv" {
date[$2] = $3
data[$2] = $0
used[$2] = 0
}
FILENAME == "input1.csv" {
if ($2 in date) {
used[$2] = 1
if ($3 < date[$2])
print data[$2]
else
print $0
} else {
print $0
}
}
END {
for (key in used) {
if (used[key] == 0)
print data[key]
}
}
注意:
修改强>
Heeding @ JonathanLeffler关于我确定正在处理哪个文件的方式的评论我想提供一个替代版本,可能(或可能不是:-))比检查NR=FNR
更直接理解。但是,它仅适用于awk
的足够近期版本,它们能够将数组的大小返回为length(array)
:
BEGIN {
FS = ","
}
{
# The following effectively creates an array entry for each filename found (for "known" filenames existing entries are overwritten).
files[FILENAME] = 1
# check the number of files we have so far
if (length(files) == 1) {
# we are still in the first file
date[$2] = $3
data[$2] = $0
used[$2] = 0
} else {
# we are in the second file (or any other following file)
if ($2 in date) {
used[$2] = 1
if ($3 < date[$2])
print data[$2]
else
print $0
} else {
print $0
}
}
}
END {
for (key in used) {
if (used[key] == 0)
print data[key]
}
}
此外,如果您需要根据第二行对输出进行排序,则可以将此呼叫替换为awk
:
awk -f script.awk input2.csv input1.csv | sort -t "," -n -k 2 > result.csv
后者当然适用于两种版本的脚本。
答案 1 :(得分:2)
由于file1
非常大但file2
非常小(5-10个条目),因此您需要先将所有file2
读入内存,然后处理重复值。因此,您将拥有一个使用新数据记录索引的数组;您还应该在单独的数组中记录每条记录的日期。然后,当您阅读主文件时,您将查找记录编号和数组中的日期,如果需要,请将保存的新记录替换为传入的旧记录。
您的大纲脚本大部分都在那里。它更复杂,因为你没有保存日期。这或多或少有效:
awk -F, '
FNR == NR { if (!($2 in date) || date[$2] < $3) { date[$2] = $3; line[$2] = $0; } next; }
{ if ($2 in date)
{
if (date[$2] > $3)
print line[$2]
else
print
delete line[$2]
delete date[$2]
}
else
print
}
END { for (l in line) print line[l]; }' file2 file1
给定数据的示例输出:
DL,1111111100,201312051013,val,FIX01,OptIn,N,Ext1,Ext2
DL,1111111101,201312051014,val,FIX01,OptIn,Y,Ext1,Ext2
DL,1111111102,201312051017,val,FIX02,OptIn,N,Ext1,Ext2
DL,1111111103,201312051016,val,FIX01,OptIn,N,Ext1,Ext2
DL,1111111104,201312051016,val,FIX02,OptIn,Y,Ext1,Ext2
但是,如果有4条新记录,则不能保证它们按排序顺序排列,尽管它们都在列表的末尾。如果输入保证按排序顺序,则可以升级脚本以在列表中的适当位置打印新记录。您只需搜索行列表以查看是否有任何行应在当前行之前打印,如果是,则执行此操作(并删除记录以便最后不打印它们)。
请注意,输出中的唯一性取决于输入中的唯一性(file1
)。也就是说,如果输入中的字段2重复,则此代码将不会注意到。即使发现重复,当前的设计也无法做到;旧行已打印,因此打印新行只会导致复制。如果您对此感到担心,可以设计awk
脚本以将整个file1
保留在内存中,并且只在处理完整个输入时打印任何内容。毋庸置疑,这比目前的设计使用了更多的内存,并且因此通常效率较低。不过,如果需要,可以做到。