我编写了以下bash脚本将毫秒转换为Days:Hours:Minutes:Seconds:使日志文件更具可读性的毫秒:
#!/bin/bash
### Constants ###
CON_DAYS=.0000000115741
CON_HOURS=.000000277778
CON_MINUTES=.000066667
CON_SECONDS=.001
### Variables ###
INPUT="$1"
cat $INPUT | awk -v CON_HOURS=$CON_HOURS -v CON_MINUTES=$CON_MINUTES -v CON_SECONDS=$CON_SECONDS -v CON_DAYS=$CON_DAYS '
{ $1=substr($0,0,10) }
{ MILLISECONDS = $1 }
{ DAYS = int(MILLISECONDS * CON_DAYS) }
{ MILLISECONDS = MILLISECONDS - int( DAYS / CON_DAYS ) }
{ HOURS = int(MILLISECONDS * CON_HOURS) }
{ MILLISECONDS = MILLISECONDS - int(HOURS / CON_HOURS) }
{ MINUTES = int(MILLISECONDS * CON_MINUTES) }
{ MILLISECONDS = MILLISECONDS - int(MINUTES / CON_MINUTES) }
{ SECONDS = int(MILLISECONDS * CON_SECONDS) }
{ MILLISECONDS = MILLISECONDS - int( SECONDS / CON_SECONDS ) }
{ $1 = DAYS":"HOURS":"MINUTES":"SECONDS":"MILLISECONDS"ms" }
{print}'
exit
输入文件部分:
1882224617mS ATMChannel: [1] CMLinkLayer Rx: 'DialDigits' (ls)
1882224617mS ATMIO: [1] TONE DIAL (11 digits)
1882224617mS ATMChannel: [1] StateChange Connected->ToneDialing
有几行输出显示它无法正常工作:
22:19:224:14:186ms ATMChannel: [1] CMLinkLayer Rx: 'DialDigits' (ls)
22:19:224:14:186ms ATMIO: [1] TONE DIAL (11 digits)
22:19:224:14:186ms ATMChannel: [1] StateChange Connected->ToneDialing
经过几个小时的故障排除后,我无法找到错误。任何帮助将不胜感激。
答案 0 :(得分:4)
分为毫秒和秒,使用GNU日期,您应该更容易获得结果
#!/bin/bash
INPUT="$1"
while read t rest
do
ms=$(echo $t|sed -r "s/.*(.....)$/\1/") # get Milliseconds 617mS
se=$(echo $t|sed -r "s/(.....)$//") # get seconds 1882224
days=$(echo $se / 3600 / 24 |bc)
d="$days:$(date -d "1970-01-01 $se seconds" +%H:%M:%S):$ms"
echo "$d $rest"
done < $INPUT
答案 1 :(得分:3)
如果执行速度是一个问题,这将产生与接受的答案相同的输出,但它在我的机器上快了33倍(0.9s对30s,1000行文件):
#!/bin/bash
sed 's/\([[:digit:]]\{3\}\)mS/ \1mS/' "$1" | while read sec msec info; do
for scale in 86400 3600 60 1; do
num_scale=$((sec / scale))
sec=$((sec - (scale * num_scale)))
echo -n "$num_scale:"
done
echo "$msec $info"
done
效率来自以下方面:
sed
进程中完成将秒与毫秒分开,为while
循环提供信息。read
一次。date
命令的解析器,格式化程序等。虽然它没有标记在你的问题中,但默认情况下大多数UNIX上都安装了perl
,非常适合这类任务,即使是快速而肮脏的风格,它也是速度的又一步(使用相同文件的0.05s;比我上面的BASH快18倍,比接受的答案快600倍):
#!/usr/bin/perl
@scales = (86400, 3600, 60, 1);
while (<>) {
($sec, $msec, $info) = /^(\d+)(\d{3}mS)(.+)$/;
foreach $scale (@scales) {
$num_scale = sprintf("%0d", $sec / $scale);
$sec -= $scale * $num_scale;
print "$num_scale:";
}
print "$msec$info\n";
}
执行时间测试和输出验证:
$ for script in accepted.bash iscfrc.bash iscfrc.pl; do echo -n $script:; time ./$script log_1000.txt >$script.output; echo; done
accepted.bash:
real 0m30.257s
user 0m4.040s
sys 0m8.089s
iscfrc.bash:
real 0m0.881s
user 0m0.672s
sys 0m0.200s
iscfrc.pl:
real 0m0.052s
user 0m0.040s
sys 0m0.012s
$ md5sum *.output
e3a05f4f88a9d912f4ba92112dfbf709 accepted.bash.output
e3a05f4f88a9d912f4ba92112dfbf709 iscfrc.bash.output
e3a05f4f88a9d912f4ba92112dfbf709 iscfrc.pl.output
$ tail -n3 *.output
==> accepted.bash.output <==
21:18:50:24:617mS ATMIO: [1] TONE DIAL (11 digits)
21:18:50:24:617mS ATMChannel: [1] StateChange Connected->ToneDialing
21:18:50:24:617mS ATMChannel: [1] CMLinkLayer Rx: 'DialDigits' (ls)
==> iscfrc.bash.output <==
21:18:50:24:617mS ATMIO: [1] TONE DIAL (11 digits)
21:18:50:24:617mS ATMChannel: [1] StateChange Connected->ToneDialing
21:18:50:24:617mS ATMChannel: [1] CMLinkLayer Rx: 'DialDigits' (ls)
==> iscfrc.pl.output <==
21:18:50:24:617mS ATMIO: [1] TONE DIAL (11 digits)
21:18:50:24:617mS ATMChannel: [1] StateChange Connected->ToneDialing
21:18:50:24:617mS ATMChannel: [1] CMLinkLayer Rx: 'DialDigits' (ls)
答案 2 :(得分:1)
不会使用cat或awk(除非您在awk脚本中执行了所有操作)。
尝试类似
的内容#!/bin/bash
INPUT="$1"
while IFS= read -r line; do
[[ $line =~ ^[0-9]+ ]] && days=$(echo "${BASH_REMATCH[0]} / (1000 * 60 * 60 * 24)" | bc -l)
[[ $days =~ '.'[0-9]+ ]] && hours=$(echo "${BASH_REMATCH[0]} * 24" | bc -l)
[[ $hours =~ '.'[0-9]+ ]] && minutes=$(echo "${BASH_REMATCH[0]} * 60" | bc -l)
[[ $minutes =~ '.'[0-9]+ ]] && seconds=$(echo "${BASH_REMATCH[0]} * 60" | bc -l)
[[ $seconds =~ '.'[0-9]+ ]] && ms=$(echo "${BASH_REMATCH[0]} * 1000" | bc)
[[ $line =~ 'mS'(.*) ]] && line="${BASH_REMATCH[1]}"
printf "%d:%d:%d:%d:%d" "$days", "$hours", "$minutes", "$seconds", "$ms" 2>/dev/null
printf "$line\n"
done < "$INPUT"
哪个产生
21:18:50:24:616 ATMChannel: [1] CMLinkLayer Rx: 'DialDigits' (ls)
21:18:50:24:616 ATMIO: [1] TONE DIAL (11 digits)
21:18:50:24:616 ATMChannel: [1] StateChange Connected->ToneDialing