【问题标题】:parse file and date manipulation in bash with a large file使用大文件在 bash 中解析文件和日期操作
【发布时间】:2019-08-20 11:16:18
【问题描述】:

我正在寻找一种更好的方法来将日期格式转换为我想要的格式。我确实做到了,但我必须多次处理文件,因为我无法让date 一次性完成。

我的格式:
Wed Jan 30 08:00:00 2019 : misc data

我想要的格式:
30/01/2019 08:00:00 : misc data

但是,如果日期信息的格式为:
30-Jan-2019 08:00:00 : misc data

,我只能让date 处理日期信息

(注意:misc data 是一个包含许多笨重字符的长字符串)

为了实现我想要的,我正在使用:

awk '{("date --date="$3"-"$2"-"$5"\\ "$4" +%F") | getline $1;$2="";$3="";$4;$5=""} 1' oldfile | tr -s ' ' > newfile

这样做是创建一种我可以使用的格式,将其解析为字段 $1,清除字段 2、3 和 5,将其打印出来(保留字段 4 中的时间和其他数据)并去除多余的空格由空白字段留下并将其保存到新文件中。然后我必须将包含分隔符的格式(因为 date 不喜欢 / 如果使用命名月份)转换为新格式,整个过程变得太复杂了。

然后我在它上面运行另一个 awk 交换字段和分隔符。

我确信这可以简化,但现在开始太让我困惑了。

我确实意识到我应该使用date 的输出format,但是因为涉及斜线,所以一旦我包含单引号或双引号,或者尝试转义它们,我发现任何涉及多种格式的东西元素失败。

更糟糕的是,当我处理一组有限的数据(通常是由 headtail 限制的样本时,这一切都有效,但原始文件的长度约为 20,000 个条目,并且在 FNR=1043 处失败打开的文件太多。只打开一个文件,保存一个文件。我认为这是使用getline的结果。有没有办法不使用它??

【问题讨论】:

  • 我强烈建议你使用日期格式YYYY-mm-dd——这种格式是明确的,它在词汇和时间上的排序是一样的。
  • 我同意,我是 ISO8601 的大力支持者,但我不控制源文件。我只是转换为上述格式,以便与下一组需要合并的文件内联。

标签: bash date awk getline


【解决方案1】:

您无需调用date 来随机播放文本:

$ echo 'Wed Jan 30 08:00:00 2019 : misc data' |
awk '{
    mthNr = (index("JanFebMarAprMayJunJulAugSepOctNovDec",$2)+2)/3
    date = sprintf("%02d/%02d/%04d %s", $3, mthNr, $5, $4)
    sub(/^([^ ]+ +){5}/,"")
    print date, $0
}'
30/01/2019 08:00:00 : misc data

顺便说一句,too many open files 错误是因为您在每次调用 getline 后都没有关闭管道。请参阅 http://awk.freeshell.org/AllAboutGetline 了解何时以及如何稳健地使用 getline。

【讨论】:

  • awk 的力量。哈哈。我试图避免令人费解的index,并认为使用date 会更容易。我了解您的月份索引和日期sprintf,但您能解释一下sub 行发生了什么吗?这完全超出了我的想象。
  • 它只是删除了前 5 个字段,即日期+时间。每个字段都是一个非空白序列 ([^ ]+),并且字段与其他字段由空白 (<blank>+) 分隔,因此匹配前 5 个字段加上每个字段后面的分隔符是 ^([^ ]+ +){5}
【解决方案2】:

另一个awk

$ echo 'Wed Jan 30 08:00:00 2019 : misc data' | awk -F: -v OFS=: ' { t=$NF;NF--; 
    cmd="date -d\047" $0 "\047 \047+%d/%m/%Y %T\047"; if ( (cmd | getline line) > 0 ) 
    close(cmd); print line,t}'
30/01/2019 08:00:00: misc data
$

【讨论】:

  • 应该是 date="N/A"; if ( (cmd | getline line) > 0 ) date=line; close(cmd); print date,t 或类似的值,否则如果 getline 失败,您将保持管道打开并悄悄打印 getline 成功的 line 的最后一个值。
猜你喜欢
  • 1970-01-01
  • 2015-07-25
  • 2012-09-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多