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

Bash 在unix shell中用对值调用函数的结果替换值,bash,shell,sed,awk,Bash,Shell,Sed,Awk,我有一个如下所示的文本流: ---------------------------------------- s123456789_9780 heartbeat:test @ 1344280205000000: '0' heartbeat:test @ 1344272490000000: '0' ---------------------------------------- s123456789_9780 heartbeat:test @ 20

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

----------------------------------------
s123456789_9780
  heartbeat:test       @ 1344280205000000: '0'
  heartbeat:test       @ 1344272490000000: '0'
----------------------------------------
s123456789_9780
  heartbeat:test       @ 2012/06/08-12:10:05: '0'
  heartbeat:test       @ 2012/06/08-10:01:30: '0'
这些长数字是以微秒为单位的时间戳。我希望通过某种管道来运行这个输出,将这些时间戳更改为更人性化的日期

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

我想以这样的方式结束:

----------------------------------------
s123456789_9780
  heartbeat:test       @ 1344280205000000: '0'
  heartbeat:test       @ 1344272490000000: '0'
----------------------------------------
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脚本中生成的,并且我不希望依赖于外部文件)。

我也希望看到一个
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}
隐式地是默认块)。

这主要是在
bash
中使用
日期
命令执行的:

#!/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'
.
#/bin/bash
如果=$
边读边读;做
中的“$a”格
*“@”[0-9]*)pre=${a%@*}
a=${a#$pre@}
post=${a##*:}
a=${a%?:$post}
echo“$pre$(日期--date=@$a+%Y/%d/%m-%H:%m:%S):$post”
;;
*)回声“$a”;;
以撒
完成怎么样:

while read s1 at tm s2
do 
    tm=${tm%000000:}
    echo $s1 $at $(date --date @$tm +%Y/%d/%m-%H:%M:%S)
done < yourfile
在tm s2读取s1时
做
tm=${tm%000000:}
echo$s1$at$(日期--date@$tm+%Y/%d/%m-%H:%m:%S)
完成你的文件

Bash加上一点sed,保留输入的空白:

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
这可能适用于您(GNU-sed):

说明:

  • /@/!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/
    删除字符串的原始部分

这个程序在没有时间戳的行上运行--不过我喜欢它的简单性。我认为
gsub
不起作用--我运行这个程序,得到的日期是42600513/23/11-15:33:20,这有点不对劲。:-)这很奇怪,我已经把我得到的添加到了答案中。您使用的是哪个版本的
awk
?我已经用
gawk
对其进行了测试。我使用的是GNU awk 3.1.6。如果我删除
strftime
行,那么我会得到很长的时间戳。也许可以尝试使用您使用的原始格式字符串<代码>%Y/%d/%m-%H:%m:%S
。这似乎不起作用——如果我将regexp从
“{7}$”
更改为
“000000:”
它确实起作用。但是,保留空白太棒了!我将sed表达式改为使用
#
而不是
/
,这样我就不必做所有的转义操作了,但除此之外,它的效果非常好!为了我的启发,
parts=($REPLY)
行只是使用IFS将
$REPLY
拆分成一个数组,对吗?没错。更改sed的分隔符是个好主意;我希望我记得那是一个选择。我将更新答案以使用#。e标志适用于文件,但不适用于函数。我使用的是GNU-sed版本4.2.1。@michelpm这可能只适用于linux/unix bash环境中的GNU-sed。@正如我所说,我使用的是GNU-sed版本4.2.1,我在Ubuntu 13.04上测试了bash和zsh。它确实适用于可执行文件,但不适用于函数
square(){echo$($1*$1))}
seq(){for((i=0;i<$1;i++);do echo$i;done}
seq 10 | sed's/[0-9]*/square&/ge'
抱怨square函数不存在。如果我将square函数转换为
square.sh
,并将sed改为调用该文件,它确实可以工作。有什么想法吗?@potong很管用:
sed's/[0-9]*/echo\$(&*&))/ge'