awk |在文件中添加新行或更新现有行
我想在file2的基础上更新file1。如果文件2中有任何行是新的,则应将其添加到文件1中。如果file2中的任何行已经在file1中,那么如果file2中的时间更长,则使用file2中的行更新该行 文件1 文件2 新文件1awk |在文件中添加新行或更新现有行,awk,Awk,我想在file2的基础上更新file1。如果文件2中有任何行是新的,则应将其添加到文件1中。如果file2中的任何行已经在file1中,那么如果file2中的时间更长,则使用file2中的行更新该行 文件1 文件2 新文件1 DL,1111111100,201312051013,val,FIX01,OptIn,N,Ext1,Ext2 DL,1111111101,201312051014,val,FIX01,OptIn,Y,Ext1,Ext2 DL,1111111102,201312051
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
注:
第二个字段在输出中应该是唯一的。
添加新值:文件2中值11111111 04的最新第二个字段在日期列第三个字段的基础上是较新的201312051016,然后是旧值201312051014。
更新现有值:根据第3列中的日期更新11111 02的新值
文件1非常大,而文件2只有5-10个条目。
第二个字段为11111111 01的行不需要更新,因为与文件2中的新日期201312041013相比,它在文件1中的条目已具有最新日期201312051014。
我没有在这方面做太多尝试,因为作为初学者,它的情况确实很复杂
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];
}
由于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
然而,如果有4条新记录,不能保证它们是按顺序排列的,尽管它们都在列表的末尾。如果保证输入按顺序排序,则可以升级脚本以在列表中的适当位置打印新记录。您只需搜索行列表,查看是否有任何行应在当前行之前打印,如果有,则执行此操作并删除记录,以便它们不会在末尾打印
请注意,输出中的唯一性取决于输入文件1中的唯一性。也就是说,如果重复输入中的字段2,则此代码不会注意到。即使发现了复制品,也无法对当前设计进行任何处理;旧行已打印,因此打印新行只会导致重复。如果您担心这一点,那么可以设计awk脚本将整个file1保存在内存中,并且只在处理完整个输入后才打印任何内容。不用说,这比当前的设计使用了更多的内存,并且通常会因此而降低效率。不过,如果需要,也可以这样做。因为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
然而,如果有4条新记录,不能保证它们是按顺序排列的,尽管它们都在列表的末尾。如果保证输入按顺序排序,则可以升级脚本以在列表中的适当位置打印新记录。您只需搜索行列表,查看是否有任何行应在当前行之前打印,如果有,则执行此操作并删除记录,以便它们不会在末尾打印
请注意,输出中的唯一性取决于输入文件1中的唯一性。也就是说,如果重复输入中的字段2,则此代码不会注意到。即使发现了复制品,也无法对当前设计进行任何处理;旧行已打印,因此打印新行只会导致重复。如果您担心这一点,那么可以设计awk脚本将整个file1保存在内存中,并且只在处理完整个输入后才打印任何内容。不用说,这比当前的设计使用了更多的内存,并且通常会因此而降低效率。不过,如果需要,也可以这样做。假设您可以按如下方式启动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]
}
}
此外,如果您需要根据第二行对输出进行排序,您可以用以下内容替换对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]
}
}
此外,如果您需要根据第二行对输出进行排序,您可以用以下内容替换对awk的调用:
当然,后者适用于两种版本的脚本。问题是什么?我不知道你想达到什么目的。试着解释一下你想要什么,而不是仅仅张贴一些文件和难以理解的便条-然后有人会帮助你。如果我不能正确解释,我道歉。。现在我也添加了一个小摘要。。如果我需要解释,请告诉我。问题是什么?我不知道你想达到什么目的。试着解释一下你想要什么,而不是仅仅张贴一些文件和难以理解的便条-然后有人会帮助你。如果我不能正确解释,我道歉。。现在我也添加了一个小摘要。。如果我需要解释mote,请告诉我。基本逻辑看起来很合理,与我使用的非常相似,我从数组中删除了使用过的条目;您有用于传递相同信息的辅助数组。但是,通过键入这两个文件名,您的代码会变得非常脆弱,而我的代码可以处理input2.csv和input1.csv,就像处理file2和file1一样。在某些方面,FNR==NR习惯用法不是那么令人愉快,但它确实可以很好地将第一个文件与其他文件区别对待。。您的解决方案也很有效,Jonathan….:基本逻辑看起来很合理,与我使用的非常相似,我从数组中删除了使用过的条目;您有用于传递相同信息的辅助数组。但是,通过键入这两个文件名,您的代码会变得非常脆弱,而我的代码可以处理input2.csv和input1.csv,就像处理file2和file1一样。在某些方面,FNR==NR习惯用法不是那么令人愉快,但它确实可以很好地将第一个文件与其他文件区别对待。。您的解决方案也很有效,Jonathan….:谢谢你,乔纳森。。这对你来说既快又容易。。你能解释一下第二个条件吗。。?第二个if是从{..这是在第一个if条件之后的文件上的第二个循环吗?有三个块。第一个是FNR==NR块;它处理处理的第一个文件aka file2,因为此时文件记录号与整个记录号匹配,并且下一个跳过给定行的其余处理。下一个块就是您要处理的块参考我的想法,它适用于第二个文件中的每一行。它查看记录编号是否已知,如果是,并且替换日期比文件file1中的日期更晚,则它打印修订;无论哪种方式,它都会删除记录以保持清洁。如果记录不在file2数据中,则记录Is简单地打印。第三个块是结束块。它查找行数组中仍保留的所有记录并打印它们;它们与文件1中的任何内容都不匹配,因此必须添加它们。谢谢Jonathan..这很快,很容易..您能否解释第二个if条件..?第二个if从{..这是在第一个if条件之后的文件上的第二个循环吗?有三个块。第一个是FNR==NR块;它处理处理的第一个文件aka file2,因为此时文件记录号与整个记录号匹配,并且下一个跳过给定行的其余处理。下一个块就是您要处理的块参考我的想法,它适用于第二个文件中的每一行。它查看记录编号是否已知,如果是,并且替换日期比文件file1中的日期更晚,则它打印修订;无论哪种方式,它都会删除记录以保持清洁。如果记录不在file2数据中,则记录Is只是打印。第三个块是结束块。它查找行数组中仍保留的所有记录并打印它们;它们与file1中的任何内容都不匹配,因此必须添加它们。
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 -f script.awk input2.csv input1.csv | sort -t "," -n -k 2 > result.csv