awk |在文件中添加新行或更新现有行

awk |在文件中添加新行或更新现有行,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

我想在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,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