awk: 无法打开管道打开的文件太多

awk: cannot open pipe Too many open files

我有一个具有以下结构的文件

#data 28-Sep-2020 16:48:04
#Version 1.1
#start
27-Sep-2020 16:00:22.00      83004     83.004784    uA               1
27-Sep-2020 16:01:22.00      82821     82.821602    uA               1
27-Sep-2020 16:02:22.00      82786     82.786552    uA               1
27-Sep-2020 16:03:22.00      82666     82.666336    uA               1
27-Sep-2020 16:04:22.00      82837     82.837242    uA               1
27-Sep-2020 16:05:22.00      82579     82.579857    uA               1
27-Sep-2020 16:06:22.00      82693     82.693413    uA               1
27-Sep-2020 16:08:22.00      82700     82.700043    uA               1
27-Sep-2020 16:09:22.00      82646     82.646797    uA               1
27-Sep-2020 16:10:22.00      82794     82.794540    uA               1
27-Sep-2020 16:11:22.00      82600     82.600845    uA               1
27-Sep-2020 16:12:22.00      82815     82.815422    uA               1
27-Sep-2020 16:13:22.00      82866     82.866974    uA               1

我试图在文件中追加 %Y %-m %-d 日期格式的第一列,%-H %-M 日期格式的第二列,最后是第 4 列:

2020 9 27     16 0     83.004784
2020 9 27     16 1     82.821602
2020 9 27     16 2     82.786552    
2020 9 27     16 3     82.666336
2020 9 27     16 4     82.837242
2020 9 27     16 5     82.579857
2020 9 27     16 6     82.693413
2020 9 27     16 7     82.700043
2020 9 27     16 8     82.646797
2020 9 27     16 9     82.794540
2020 9 27     16 10    83.004784
2020 9 27     16 11    82.600845
2020 9 27     16 12    82.815422
2020 9 27     16 13    82.866974

我想过使用 getlinedate 命令,所以这就是我在一行中所做的(为了清楚起见,我只是在这里拆分命令)对于第一列

$awk '{if(NR>=4)parsedate="date --date="" +\"%Y %-m %-d\""
                cmd | getline mydate
                close(parsedate);
       if(NR>=4 && NR<=10) print mydate, }' inputfile

这工作得很好而且很快。当我尝试使用以下单行

对第二列执行相同操作时
$awk '{if(NR>=4)parsedate="date --date="" +\"%-H %-M\""
                cmd | getline mydate close(parsedate);
       if(NR>=4 && NR<=10) print mydate, }' inputfile

它慢得多(输入文件是一个大文件所以我认为它忽略了 if 语句)并且尽管它打印出它应该打印的内容(即第 4 行的 16 0 83.004784 ) returns 出现以下错误

awk: cmd. line:1: (FILENAME=inputfile FNR=1023) fatal: cannot open pipe `date --date=08:59:22.00 +"%-H %-M"' (Too many open files)

令我感到奇怪的是,我确实在使用 close() 命令,所以我不知道它为什么会抱怨,而且只在小时情况下抱怨。

欢迎任何想法!

首先,错误可能是因为没有调用close。但即使解决了这个问题,如果我们为每个日志行调用系统 date,并且通常日志有很多行,那么我们的脚本就会非常慢。

因此必须使用 GNU awk time functions or even better, if requirements allow, like here, to use only string functions。通常我们只是在 split()match() 的帮助下重新排列字段,但如果有月份要转换为数字,则有一种标准方法可以做到。

awk 'NR>3{ split(, dat, "-"); split(, tim, ":")
     m=(index("JanFebMarAprMayJunJulAugSepOctNovDec", dat[2])+2)/3
     print dat[3], m, dat[1], tim[1], tim[2],  }' file

我们用所有 3 个字母的月份定义字符串,对于要转换的任何参数,我们得到此子字符串开始的 index(),(Jan 是第一个字符,Feb 4, Mar 7 等,所以 (i+2)/3 将给出月份数。

输出:

2020 9 27 16 00 83.004784
2020 9 27 16 01 82.821602
2020 9 27 16 02 82.786552
2020 9 27 16 03 82.666336
2020 9 27 16 04 82.837242
2020 9 27 16 05 82.579857
2020 9 27 16 06 82.693413
2020 9 27 16 08 82.700043
2020 9 27 16 09 82.646797
2020 9 27 16 10 82.794540
2020 9 27 16 11 82.600845
2020 9 27 16 12 82.815422
2020 9 27 16 13 82.866974

这些是数据,您可以使用 printf 进行任何格式设置。