【问题标题】:Sed print with evaluated date command on back reference带有评估日期命令的 Sed 打印在反向引用上
【发布时间】:2016-05-22 19:42:05
【问题描述】:

我有一个文件(通常是这样),其中 *nix 时间中的日期是从纪元开始的秒数,然后是一条消息和一个我想要选择的最终“线程”字段。全部用“|”分隔从 sqlite DB 导出...

例如

1306003700|SENT|21
1277237887|SENT|119
1274345263|SENT|115
1261168663|RECV|21
1306832459|SENT|80
1306835346|RECV|80

基本上,我可以很容易地使用 sed 来选择和打印与“线程”字段匹配的行,并使用消息打印相应的时间,因此:

> cat file | sed -n "s/^\([0-9]*\)\|\(.*\)\|80$/\1 : \2/p"
1306832459 : SENT
1306835346 : RECV

但我真正想做的也是通过unix date命令传递时间字段,所以:

> cat file | sed -n "s/^\([0-9]*\)\|\(.*\)\|80$/`date -r \1` : \2/p"

但这似乎不起作用 - 即使它似乎接受它。它只是打印出相同的(纪元开始)日期:

Thu  1 Jan 1970 01:00:01 BST : SENT
Thu  1 Jan 1970 01:00:01 BST : RECV

我如何/可以评估/插入对日期命令的反向引用 \1?

也许 sed 不是匹配这些行的方法(并一次性格式化输出)...

【问题讨论】:

    标签: bash unix date sed


    【解决方案1】:

    awk 非常适合。

    awk -F"|" '$3 == '80' { print system("date -r " $1), ":", $2 }' myfile.txt
    

    应该可以。(虽然不能保证系统调用是正确的,没有测试过)

    【讨论】:

    • 我喜欢它的“单行”方面 - 但是,系统调用似乎直接在换行符上打印,并且(奇怪的是)返回码然后在冒号之前打印(零)为 $1 .例如 2011 年 5 月 31 日星期二 16:18:08 BST \n 0 : SENT \n
    • @Tim 不幸的是,我不确定如何改变这种行为。 Perl 可能是更好的选择
    • 是的 - 不用担心。羞耻,因为我总是喜欢 awk 和 sed 对这些东西的简洁性,但这似乎是它们如何调用进一步命令的缺陷。现在将使用 Perl。
    【解决方案2】:

    这个纯粹的 bash

    wanted=80
    (IFS=\|; while read sec message thread
    do
            [[ $thread == $wanted ]] && echo $(date -r $sec) : $message
    done) < datafile.txt
    

    打印

    Tue May 31 11:00:59 CEST 2011 : SENT
    Tue May 31 11:49:06 CEST 2011 : RECV
    

    为了安全起见,您可以在“ ”中引用变量...

    【讨论】:

      【解决方案3】:

      Perl 在这里很方便:

      perl -MPOSIX -F'\|' -lane '
          next unless $F[2] == "80";
          print(strftime("%Y-%m-%d %T", localtime $F[0]), " : ", $F[1])
      ' input.file
      

      【讨论】:

      • 完全按照它说的那样工作。不是那么紧凑 - 但旧的 perl 很好。
      【解决方案4】:

      这可能对你有用:

       sed -n 's/^\([0-9]*\)|\(.*\)|80$/echo "$(date -d @\1) : \2"/p' file | sh
      

      或者如果你有 GNU sed:

       sed -n 's/^\([0-9]*\)|\(.*\)|80$/echo "$(date -d @\1) : \2"/ep' file
      

      【讨论】:

        【解决方案5】:

        使用 awk

        $(awk -F'|' '/80$/{printf("echo $(date -d @%s) : %s;",$1,$2);}' /path/to/file)
        

        【讨论】:

          【解决方案6】:

          date 命令将在sed 命令之前执行。

          为这项工作打破 perl 或 python 可能是最容易的,或者您可以使用某种 bash 循环,否则。

          【讨论】:

            【解决方案7】:

            受上述 Rafe 回答的启发:

            awk -F"|" '$3 == '80' { system("date -d @" $1 " | tr -d \"\n\""); print " :", $2 }' myfile.txt
            

            对于我的日期版本,似乎-d 是参数,而不是-r,并且它需要一个前导@。这里的另一个变化是 system 调用执行(因此 date 实际上执行打印、换行和所有操作 - 因此是 tr)并返回退出代码。我们并不关心打印退出代码 (0),因此我们将 system 调用移到任何 awk prints 之外。

            【讨论】:

              猜你喜欢
              • 2013-10-22
              • 1970-01-01
              • 2015-12-12
              • 1970-01-01
              • 2018-10-25
              • 1970-01-01
              • 2015-01-18
              • 2014-11-21
              • 1970-01-01
              相关资源
              最近更新 更多