【问题标题】:Parsing and making modifications in file content解析和修改文件内容
【发布时间】:2019-03-04 06:28:08
【问题描述】:

我有一个应用程序,它生成的文件包含用逗号 (,) 分隔的各种数据行。

例如:

hostname,file_name,type,status,size(b),date,owner(user),owner(group)
server1,/var,dir,ACT_VER,29987,2007-12-03 15:52:43.000,root,root
server2,/DATA_File.out,file,ACT_VER,299076487,2008-10-15 05:12:23.000,marcos,root
server3,/opt,dir,29987,2009-05-03 00:13:23.000,user1,group1
server4,/var/tmp/xxz.zip,file,MOD_VER,400,2007-12-03 15:52:43.000,root,root
server1,/usr,dir,34299876,2006-12-03 15:52:43.000,root,root
server3,/local/home,dir,MOD_VER,400,2009-05-03 00:13:23.000,user2,group1

预期输出:

hostname,file_name,type,status,size(b),date,owner(user),owner(group)
server1,/var,dir,ACT_VER,29987,2007-12-03 15:52:43,root,root
server2,/DATA_File.out,file,ACT_VER,299076487,2008-10-15 05:12:23,marcos,root
server3,/opt,dir,,29987,2009-05-03 00:13:23,user1,group1
server4,/var/tmp/xxz.zip,file,MOD_VER,400,2007-12-03 15:52:43,root,root
server1,/usr,dir,,34299876,2006-12-03 15:52:43,root,root
server3,/local/home,dir,MOD_VER,400,2009-05-03 00:13:23,user2,group1

第一个查询:有时文件会丢失第 4 列 status 中的信息,可以是 ACT_VERMOD_VERTCH_VERCRT_VER。我想在缺少status 的文件中添加一个额外的逗号(,)。

第二次查询:date 列中的数据在 `YYYY-MM-DD HH:MM:SS.MsMs (Ms=millisecond) 中。我想忽略毫秒。

我正在寻找 awk 中的一些东西(其他任何东西)来做这两者,这在处理中很轻,因为代码必须解析数百万行。

对于第一个查询,我尝试了这个(以及几个替代品),但没有奏效

cat file | awk -F, 'BEGIN {OFS=","}{if ($4 !~ /VER/) $4=",$4";}{print $0}'

我还没有开始处理第二个查询。

我也想知道,当*VER* 丢失时,我是否应该将整个文件放入数组中并处理第4 个元素以包含额外的逗号(,)并删除第6 个元素中的.000

不确定哪一个进程占用最少。

我在 RHEL 6.7 操作系统上使用 shell 脚本

【问题讨论】:

  • 显示您所显示输入的预期输出。
  • @anubhava 谢谢,我完全忘记了。我已经编辑了我的查询。
  • 上次编辑有一些错误。我已经更正了。
  • @Marcos:您的输出仍然不正确 server4 仍然有 000 在日期
  • @Inian 已更新。

标签: shell parsing awk


【解决方案1】:

分两步完成,

  1. 对于不包含$4VER 的行,在实际$4 之前插入,。由于这里,是输入输出字段分隔符,所以不能直接使用FS
  2. 对于日期列上的所有行,即$6,使用. 上的split() 函数并打印没有000 的部分

    awk 'function splitdate(var) {
             n=split(var,a,".")
             return a[1] 
         } 
         BEGIN{ FS=OFS="," } 
         NR>1 && $4 !~ /VER/{ $4=","$4; $5=splitdate($5); print; next }
         { $6=splitdate($6) }1' file
    

【讨论】:

    【解决方案2】:

    你可以使用这个awk:

    awk 'BEGIN{FS=OFS=","} NR>1 && NF<8 && $4 !~ /VER$/{$4 = OFS $4}
         {sub(/\.[0-9]{3},/, ",")} 1' file
    

    hostname,file_name,type,status,size(b),date,owner(user),owner(group)
    server1,/var,dir,ACT_VER,29987,2007-12-03 15:52:43,root,root
    server2,/DATA_File.out,file,ACT_VER,299076487,2008-10-15 05:12:23,marcos,root
    server3,/opt,dir,,29987,2009-05-03 00:13:23,user1,group1
    server4,/var/tmp/xxz.zip,file,MOD_VER,400,2007-12-03 15:52:43,root,root
    server1,/usr,dir,,34299876,2006-12-03 15:52:43,root,root
    server3,/local/home,dir,MOD_VER,400,2009-05-03 00:13:23,user2,group1
    

    【讨论】:

    • 这使得第一个server3和第二个server1的行有000
    • 哦,是的,没错。 $6 也可以是 $5。编辑假设只有毫秒值的字段;
    • @anubhava 它不会更新第 4 列的第 1 行。 awk 语句的第二部分也不起作用,它没有取代 .000
    • 我显示的输出中没有.000。此外,第一行的第 4 列已经有 ACT_VER,因此不需要更新。
    【解决方案3】:

    我测试没问题 GNU awk 3.1.7

    awk -F, 'BEGIN {OFS=","}{if ($4 !~ /VER/) $4=","$4;}{print $0}' temp|awk -F, 'BEGIN {OFS=","}{$6=substr($6,0,19)}{print}'
    server1,/var,dir,ACT_VER,29987,2007-12-03 15:52:43,root,root
    server2,/DATA_File.out,file,ACT_VER,299076487,2008-10-15 05:12:23,marcos,root
    server3,/opt,dir,,29987,2009-05-03 00:13:23,user1,group1
    server4,/var/tmp/xxz.zip,file,MOD_VER,400,2007-12-03 15:52:43,root,root
    server1,/usr,dir,,34299876,2006-12-03 15:52:43,root,root
    server3,/local/home,dir,MOD_VER,400,2009-05-03 00:13:23,user2,group1
    

    【讨论】:

    • 我已经测试过了,它不起作用,因此尝试了 "$4" 和 $4。
    • 用我的 cmd 测试一下
    • 第一个 awk 语句正在运行...我之前写的有点错误。此外,第二个 awk 语句有一个 temp,不确定是否需要。我运行了没有temp 的两个 awk 语句,它起作用了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-09
    • 2020-12-20
    • 2020-12-08
    • 2022-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多