【问题标题】:how can I use sed or awk to correct a log time format如何使用 sed 或 awk 更正日志时间格式
【发布时间】:2012-11-19 17:44:19
【问题描述】:

我目前正在编写一个处理 csv 文件的脚本,并在此过程中更正它们的某些方面。如果需要,它所做的一件事是正确的时间格式。发生两种类型的转换:

 xx:xx:xx to PTxxHxxMxxS
 10:03:45 to PT10H03M45S

我已经能够使用以下方法(见下文)做到这一点,尽管我试图找出如何使用 sed 或 awk 来加快进程。除了实际的转换过程之外,我还想记录所做的更改(比如转换 4 次值,计数器将增加到 4),我可以使用 if 轻松完成下面的语句(虽然没有显示),虽然我不太了解使用 sed/awk 做这件事。

 istimef=$( echo "$Sfcpp6" | grep ".*:.*:.*" )
                    if [ "$istimef" != "" ]; then
                            hs=$( echo "$Sfcpp6" | cut -d ':' -f 1 )
                            mn=$( echo "$Sfcpp6" | cut -d ':' -f 2 )
                            sc=$( echo "$Sfcpp6" | cut -d ':' -f 3 )
                            Sfcpp6=$( echo "PT"$hs"H"$mn"M"$sc"S" )
                            echo "$Sfcp6"
                    fi

它本质上检查时间值是否存在,然后执行转换。

【问题讨论】:

  • 在此类问题中提供示例输入(至少几行)和输出是个好主意(即使这个问题很清楚)。
  • @LevLevitsky 哎呀,对不起,应该把例子做清楚
  • 查找 bash 子字符串操作,它真的很方便 - 替换 echo | grep 使用:${varname:0:2}${varname:2:2}${varname:5:2}
  • @technosaurus 谢谢!必须检查一下,任何可以节省时间的东西哈哈

标签: file bash csv sed awk


【解决方案1】:

令人惊讶的是,您需要多少进程和子shell 来完成这项任务!我总是对人们的聪明才智和创造力感到惊讶。我数了数 10 个子外壳和 4 个进程生成。

看,您可以在不产生一个进程且无需任何子shell 的情况下实现完全相同的效果。我们在这里谈论的是加速!

第一个任务,给定一个xx:yy:zz 形式的字符串,尽可能高效地将其转换为PTxxHyyMzzS(看,只有一个命令!和一个内置命令!没有sed!):

$ string='12:34:56'
$ printf -v transformed 'PT%sH%sM%sS' ${string//:/ }
$ # Done! Don't believe me?
$ echo "$transformed"
PT12H34M56S

现在,在执行此操作之前,您可能需要检查字符串是否为xx:yy:zz 形式。为此退出grep。只需这样测试它:

if [[ "$string" = *:*:* ]]; then
    echo "ok"
else
    echo "not ok"
fi

因此,您向我们展示的部分脚本会更有效率:

if [[ "$Sfcpp6" = *:*:* ]]; then
    printf -v Sfcp6 'PT%sH%sM%sS' ${Sfcpp6//:/ }
    echo "$Sfcp6"
fi

总计:0 个子外壳,0 个进程。

或者,如果您的目标只是回显转换后的字符串:

if [[ "$Sfcpp6" = *:*:* ]]; then
    printf 'PT%sH%sM%sS\n' ${Sfcpp6//:/ }
fi

【讨论】:

  • +1 花时间进行长时间的解释、良好的建议和幽默
  • 谢谢!实际上一直在为一门课程做一个最终项目,该课程涉及获取三个数据源(在本例中为 2 个 xls 文件和一个 xml),清理/更正数据,然后将数据输出到 mysql 服务器。教授建议使用 php,尽管我决定使用 cgi 页面(bash 页面)并有一个额外的脚本来处理文件。我的脚本的第一个版本大约需要 7 秒才能完成,但是在根据我一直在问的所有问题重做代码后,我能够将其平均缩短到 1 秒以上 :)
  • 如果您想查看最终产品本身,只需下载此 zip 文件eatmyrice.org/FZIP.zip,其中包含两个 xls 文件和 xml 文件,然后转到此 url eatmyrice.org/xmlparse.html文件上传表单,上传 zip 并按提交,之后它会执行它的操作,最后在最后显示 so stats 以及最终结果的 .csv 版本(也将它们上传到 mysql,尽管我更愿意保留访问私有),如果您决定尝试一下,请告诉我您的想法,对这里的结果非常满意
【解决方案2】:

sed 解决方案:使用\(...\) 捕获数字,字符类[0-9] 匹配任意数字。

sed 's/\([0-9][0-9]\):\([0-9][0-9]\):\([0-9][0-9]\)/PT\1H\2M\3S/'

【讨论】:

  • 完美运行,谢谢!但是有一个问题,是否可以让 sed 记录它所做的更改?例如,当它改变时间值时增加一个计数器或类似的东西
  • 您可以通过 grepping 模式并将其管道传输到 wc 来预先确定数字
【解决方案3】:

如果你想计算被替换的行数:

perl -pe '
    END{print "count=$count\n"}
    s/(\d{2}):(\d{2}):(\d{2})/PT$1H$2M$3S/ && $count++
' file.txt

【讨论】:

    【解决方案4】:

    @choroba 发布的这个 sed 解决方案的 GNU awk 等效项:

    sed 's/\([0-9][0-9]\):\([0-9][0-9]\):\([0-9][0-9]\)/PT\1H\2M\3S/'
    

    会非常相似:

    awk '{print gensub(/([0-9][0-9]):([0-9][0-9]):([0-9][0-9])/,"PT\\1H\\2M\\3S","")}'
    

    但是可以对 awk 解决方案进行简单修改,以解决您的问题“是否可以让 sed 记录它所做的更改?”:

    awk '{orig=$0; $0=gensub(/([0-9][0-9]):([0-9][0-9]):([0-9][0-9])/,"PT\\1H\\2M\\3S",""); print} $0 != orig{count++} END{printf "%d changes made.\n",count}'
    

    虽然 sed 解决方案不能。

    【讨论】:

      猜你喜欢
      • 2013-08-29
      • 1970-01-01
      • 1970-01-01
      • 2011-10-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-13
      相关资源
      最近更新 更多