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
我想过使用 getline
和 date
命令,所以这就是我在一行中所做的(为了清楚起见,我只是在这里拆分命令)对于第一列
$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
进行任何格式设置。
我有一个具有以下结构的文件
#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
我想过使用 getline
和 date
命令,所以这就是我在一行中所做的(为了清楚起见,我只是在这里拆分命令)对于第一列
$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
进行任何格式设置。