【问题标题】:awk: cannot open pipe Too many open filesawk:无法打开管道打开的文件太多
【发布时间】:2021-01-15 07:43:29
【问题描述】:

我有一个结构如下的文件

#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 日期格式的第二列,最后是第四列:

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="$1" +\"%Y %-m %-d\""
                cmd | getline mydate
                close(parsedate);
       if(NR>=4 && NR<=10) print mydate, $4}' inputfile

这运行良好且快速。当我尝试使用以下单行对第二列执行相同操作时

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

它明显变慢(输入文件是一个大文件,所以我认为它忽略了if 语句),虽然它打印出它应该打印的内容(即第 4 行的16 0 83.004784)它返回以下错误

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() 命令,所以我不知道它为什么会抱怨,而且只是在小时的情况下。

欢迎提出任何想法!

【问题讨论】:

    标签: awk pipe getline


    【解决方案1】:

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

    所以必须使用 GNU awk time functions 或者更好,如果要求允许,像这里一样,只使用 string functions。通常我们只是重新排列字段,在split()match() 的帮助下,但如果有几个月要转换为数字,有一个标准的方法来做。

    awk 'NR>3{ split($1, dat, "-"); split($2, tim, ":")
         m=(index("JanFebMarAprMayJunJulAugSepOctNovDec", dat[2])+2)/3
         print dat[3], m, dat[1], tim[1], tim[2], $4 }' 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 进行任何您可能想要的格式。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-04-02
      • 1970-01-01
      • 2015-12-17
      • 2014-06-23
      • 1970-01-01
      • 1970-01-01
      • 2012-08-14
      相关资源
      最近更新 更多