Awk getline需要越来越多的时间

Awk getline需要越来越多的时间,awk,Awk,有一个(G | M)awk脚本,用于根据内容将源文件中的行重新分发到不同的文件中。例如,根据行时间戳将一组源数据分片到单独的日期文件中 它足够快,直到我需要添加一个csv标题行。源数据是无序的,因此我考虑使用if(getline

有一个(G | M)awk脚本,用于根据内容将源文件中的行重新分发到不同的文件中。例如,根据行时间戳将一组源数据分片到单独的日期文件中

它足够快,直到我需要添加一个csv标题行。源数据是无序的,因此我考虑使用
if(getline<(fname)<0){print cols>fname}
在第一次触摸时使用头行创建每个目标文件

我知道,对每行源数据进行此测试可能会很昂贵,但似乎随着目标文件的创建,每个
getline
测试都会花费更长的时间,因为处理源文件的速度变慢。经济放缓是性能问题

这个过程也在GNU并行模式下运行,因此在挂起系统调用时,
system-f
测试不起作用

关于如何在创建带有标题的文件时解决性能问题的建议?希望将此脚本保留在Awk中,因为其他逻辑已经就位


作为任务的一个示例,我有来自多个主机的日志,这些日志需要根据日志条目的日期合并到文件中:

date, time, measure
2017-01-01, 00:00, 10
2017-01-01, 01:00, 20
2017-01-03, 00:05, 30
2017-01-02, 02:10, 40
2017-01-03, 00:00, 50
此脚本的结果将是基于日期列的3个文件:

文件名:20170101.log

date, time, measure
2017-01-01, 00:00, 10
2017-01-01, 01:00, 20
文件名:20170102.log

date, time, measure
2017-01-02, 02:10, 40
文件名:20170103.log

date, time, measure
2017-01-03, 00:05, 30
2017-01-03, 00:00, 50

在需要包含列标题之前,运行此日志重组是快速而简单的。似乎随着目标文件的增长,
getline
操作每次调用所需的时间更长。其他示例显示了使用
system
调用
test-f
来验证文件的存在,但这也是一个昂贵的操作,似乎挂在GNU并行模式下。

我认为我会采取的方法是在输入出现时维护一组输出文件/管道,并根据数组成员身份而不是输出文件的存在添加标头。测试数组成员资格应该非常快,至少与在shell中生成
测试相比是如此

大概是这样的:

BEGIN {
  getline header                # this assumes we'll see a header as our
}                               # first line of input. Use whatever works.

{
  outfile=$1 ".log"             # or whatever..
  if (!(outfile in a)) {
    print header > outfile      # create the file with the header,
    a[outfile]                  # and record the output file.
  }
  print > outfile               # shard
}
这样就无需触摸文件系统来测试是否存在,但如果您有要附加的现有文件,则可能会出现问题。为此,您可能需要在
BEGIN
块中预填充数组:

BEGIN {
  getline header
  cmd="ls -d *.log 2>/dev/null"
  while (cmd | getline outfile) a[outfile]
  close(cmd)
}

{
  outfile=$1 ".log"
  if (!(outfile in a)) {
    print header > outfile
    a[outfile]
  }
  print >> outfile
}

注意:这个变体解析
ls
(我知道是呀)以获得一个文件列表来预填充数组,然后附加数据(
>
),而不是覆盖(
)。我还没有对可能包含特殊字符的日志文件进行测试。另一方面,文件名是
$1“。log“
,所以特殊性已经有点有限了。

原来我的问题是记录分隔符的问题

源文件使用RS=“\r\n”(在BEGIN块中设置),但目标文件使用“\n”作为分隔符,因为它们只是简单地打印出来的,这是在Linux上。这导致getline看不到行,因此随着目标文件的增长,getline的时间也在增长——它正在读取整个文件

我相当不雅观的解决方案是:

RS="\n"
if (getline < (fname) < 0) { print cols > fname }
RS="\r\n"
RS=“\n”
如果(getline<(fname)<0){print cols>fname}
RS=“\r\n”

如果没有
getline
,可能会有一种更简单的方法,它的性能会更好。如果您提供一个简单的测试输入和所需的输出,您将获得更多帮助。对于这一点,有比Awk更好的方法,但目前正在尝试不返工现有的相关代码。