3

我有一个看起来像这样的文本流:

----------------------------------------
s123456789_9780
  heartbeat:test       @ 1344280205000000: '0'
  heartbeat:test       @ 1344272490000000: '0'

这些长数字是以微秒为单位的时间戳。我想通过某种管道运行此输出,该管道会将这些时间戳更改为更易于人类理解的日期。

我有一个 date 命令可以做到这一点,只给出时间戳(带有以下冒号):

$ date --date=@$(echo 1344272490000000: | sed 's/.......$//') +%Y/%d/%m-%H:%M:%S
2012/06/08-10:01:30

我想结束这样的事情:

----------------------------------------
s123456789_9780
  heartbeat:test       @ 2012/06/08-12:10:05: '0'
  heartbeat:test       @ 2012/06/08-10:01:30: '0'

我认为sed不允许我匹配时间戳并将其替换为在其上调用 shell 函数的值(尽管我希望被显示错误)。也许awk可以做到?我不是很熟悉awk

对我来说似乎很棘手的另一部分是让不匹配的线条不经过修改就通过。

我当然可以编写一个 Python 程序来执行此操作,但如果可能的话,我宁愿将它保存在 shell 中(这是在 shell 脚本中生成的,我宁愿不依赖外部文件)。

4

5 回答 5

3

这可能对您有用(GNU sed):

sed '/@ /!b;s//&\n/;h;s/.*\n//;s#\(.\{10\}\)[^:]*\(:.*\)#date --date=@\1 +%Y/%d/%m-%H:%M:%S"\2"#e;H;g;s/\n.*\n//' file

解释:

  • /@ /!b退出并打印任何不包含@空格的行
  • s//&\n/在上述模式后插入换行符
  • h将模式空间 (PS) 复制到保持空间 (HS)
  • s/.*\n//删除最多并包括@后面的空格
  • s#\(.\{10\}\)[^:]*\(:.*\)#date --date=@\1 +%Y/%d/%m-%H:%M:%S"\2"#e从 PS 中剩余的内容中,对前 10 个字符以及从:字符串的结尾进行反向引用。将这些传递给date命令并将结果评估到 PS
  • H将 PS 附加到 HS 并同时插入换行符
  • g将HS复制到PS中
  • s/\n.*\n//删除字符串的原始部分
于 2012-08-09T20:26:20.793 回答
1

我也想看看一个sed解决方案,但它有点超出我的sed-fu。作为awk支持strftime,这里相当简单:

awk '
/^ *heartbeat/ { 
  gsub(".{7}$", "", $3)
  $3 = strftime("%Y/%d/%m-%T", $3)
  print " ", $1, $3
}

$0 !~ /heartbeat/' file

输出:

s123456789_9780
heartbeat:test 2012/06/08-21:10:05
heartbeat:test 2012/06/08-19:01:30

$3是微秒字段。gsub将时间戳转换为秒。

$0 !~确保打印非心跳线(隐含{ print }地是默认块)。

于 2012-08-09T17:05:19.190 回答
1

怎么样:

while read s1 at tm s2
do 
    tm=${tm%000000:}
    echo $s1 $at $(date --date @$tm +%Y/%d/%m-%H:%M:%S)
done < yourfile
于 2012-08-09T17:16:17.800 回答
1

带有一点 sed 的 Bash,保留输入的空白​​:

while read -r; do                                                                                                                                                                                                                                          
    parts=($REPLY)
    if [[ ${parts[0]} == "heartbeat:test" ]]; then
        dateStr=$(date --date=@${parts[2]%000000:} +%Y/%d/%m-%H:%M:%S)
        REPLY=$(echo "$REPLY" | sed "s#[0-9]\+000000:#$dateStr#")
    fi
    printf "%s\n" "$REPLY"
done
于 2012-08-09T17:18:18.373 回答
0

这主要是在bash使用您的date命令时完成的:

#!/bin/bash
IFS=$
while read a ; do
case "$a" in
*" @ "[0-9]*) pre=${a% @ *}
              a=${a#$pre @ }
              post=${a##*:}
              a=${a%??????:$post}
              echo "$pre$(date --date=@$a +%Y/%d/%m-%H:%M:%S):$post"
              ;;
*)            echo "$a" ;;
esac
done <<.
----------------------------------------
s123456789_9780
  heartbeat:test       @ 1344280205000000: '0'
  heartbeat:test       @ 1344272490000000: '0'
.
于 2012-08-09T17:12:11.233 回答