在unix shell中用值调用函数的结果替换值

时间:2012-08-09 16:36:26

标签: bash shell sed awk

我有一个如下所示的文本流:

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

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

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

$ 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脚本中生成的,而我宁愿不依赖于外部文件)。 / p>

5 个答案:

答案 0 :(得分: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//删除字符串的原始部分

答案 1 :(得分: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 }是默认块)。

答案 2 :(得分: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

答案 3 :(得分: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

答案 4 :(得分: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'
.